mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-01 02:38:43 +08:00 
			
		
		
		
	!1041 支付应用,增加 appKey 标识,用于不同接入方的标识
* feat[yudao-module-pay]: 更新新增和更新支付应用时校验逻辑 * fix[yudao-module-trade]: 为支付应用标识提供缺省值 * fix[yudao-module-pay]: appKey注释应用编码更新为应用标识 * feat[yudao-module-pay]: 为支付应用新增支付编码属性
This commit is contained in:
		| @@ -1,11 +1,11 @@ | ||||
| package cn.iocoder.yudao.module.pay.api.order.dto; | ||||
|  | ||||
| import lombok.Data; | ||||
| import org.hibernate.validator.constraints.Length; | ||||
|  | ||||
| import jakarta.validation.constraints.DecimalMin; | ||||
| import jakarta.validation.constraints.NotEmpty; | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| import lombok.Data; | ||||
| import org.hibernate.validator.constraints.Length; | ||||
|  | ||||
| import java.io.Serializable; | ||||
| import java.time.LocalDateTime; | ||||
|  | ||||
| @@ -18,10 +18,10 @@ public class PayOrderCreateReqDTO implements Serializable { | ||||
|     public static final int SUBJECT_MAX_LENGTH = 32; | ||||
|  | ||||
|     /** | ||||
|      * 应用编号 | ||||
|      * 应用标识 | ||||
|      */ | ||||
|     @NotNull(message = "应用编号不能为空") | ||||
|     private Long appId; | ||||
|     @NotNull(message = "应用标识不能为空") | ||||
|     private String appKey; | ||||
|     /** | ||||
|      * 用户 IP | ||||
|      */ | ||||
|   | ||||
| @@ -1,11 +1,10 @@ | ||||
| package cn.iocoder.yudao.module.pay.api.refund.dto; | ||||
|  | ||||
| import lombok.Data; | ||||
| import org.hibernate.validator.constraints.Length; | ||||
|  | ||||
| import jakarta.validation.constraints.Min; | ||||
| import jakarta.validation.constraints.NotEmpty; | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| import lombok.Data; | ||||
| import org.hibernate.validator.constraints.Length; | ||||
|  | ||||
| /** | ||||
|  * 退款单创建 Request DTO | ||||
| @@ -16,10 +15,10 @@ import jakarta.validation.constraints.NotNull; | ||||
| public class PayRefundCreateReqDTO { | ||||
|  | ||||
|     /** | ||||
|      * 应用编号 | ||||
|      * 应用标识 | ||||
|      */ | ||||
|     @NotNull(message = "应用编号不能为空") | ||||
|     private Long appId; | ||||
|     @NotNull(message = "应用标识不能为空") | ||||
|     private String appKey; | ||||
|     /** | ||||
|      * 用户 IP | ||||
|      */ | ||||
|   | ||||
| @@ -2,12 +2,12 @@ package cn.iocoder.yudao.module.pay.api.transfer.dto; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.common.validation.InEnum; | ||||
| import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum; | ||||
| import lombok.Data; | ||||
|  | ||||
| import jakarta.validation.constraints.Min; | ||||
| import jakarta.validation.constraints.NotBlank; | ||||
| import jakarta.validation.constraints.NotEmpty; | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
| @@ -19,10 +19,10 @@ import java.util.Map; | ||||
| public class PayTransferCreateReqDTO { | ||||
|  | ||||
|     /** | ||||
|      * 应用编号 | ||||
|      * 应用标识 | ||||
|      */ | ||||
|     @NotNull(message = "应用编号不能为空") | ||||
|     private Long appId; | ||||
|     @NotNull(message = "应用标识不能为空") | ||||
|     private String appKey; | ||||
|  | ||||
|     @NotEmpty(message = "转账渠道不能为空") | ||||
|     private String channelCode; | ||||
|   | ||||
| @@ -14,6 +14,7 @@ public interface ErrorCodeConstants { | ||||
|     ErrorCode APP_IS_DISABLE = new ErrorCode(1_007_000_002, "App 已经被禁用"); | ||||
|     ErrorCode APP_EXIST_ORDER_CANT_DELETE =  new ErrorCode(1_007_000_003, "支付应用存在支付订单,无法删除"); | ||||
|     ErrorCode APP_EXIST_REFUND_CANT_DELETE =  new ErrorCode(1_007_000_004, "支付应用存在退款订单,无法删除"); | ||||
|     ErrorCode APP_KEY_EXISTS = new ErrorCode(1_007_000_005, "支付应用标识已经存在"); | ||||
|  | ||||
|     // ========== CHANNEL 模块 1-007-001-000 ========== | ||||
|     ErrorCode CHANNEL_NOT_FOUND = new ErrorCode(1_007_001_000, "支付渠道的配置不存在"); | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| package cn.iocoder.yudao.module.pay.controller.admin.app.vo; | ||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| import lombok.*; | ||||
|  | ||||
| @Schema(description = "管理后台 - 支付应用信息创建 Request VO") | ||||
| @@ -8,4 +9,8 @@ import lombok.*; | ||||
| @ToString(callSuper = true) | ||||
| public class PayAppCreateReqVO extends PayAppBaseVO { | ||||
|  | ||||
|     @Schema(description = "应用标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") | ||||
|     @NotNull(message = "应用标识不能为空") | ||||
|     private String appKey; | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -17,6 +17,9 @@ public class PayAppPageItemRespVO extends PayAppBaseVO { | ||||
|     @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | ||||
|     private Long id; | ||||
|  | ||||
|     @Schema(description = "应用标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") | ||||
|     private String appKey; | ||||
|  | ||||
|     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||||
|     private LocalDateTime createTime; | ||||
|  | ||||
|   | ||||
| @@ -20,6 +20,9 @@ public class PayAppPageReqVO extends PageParam { | ||||
|     @Schema(description = "应用名", example = "小豆") | ||||
|     private String name; | ||||
|  | ||||
|     @Schema(description = "应用标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") | ||||
|     private String appKey; | ||||
|  | ||||
|     @Schema(description = "开启状态", example = "0") | ||||
|     private Integer status; | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,9 @@ | ||||
| package cn.iocoder.yudao.module.pay.controller.admin.app.vo; | ||||
|  | ||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||
| import lombok.*; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.ToString; | ||||
|  | ||||
| import java.time.LocalDateTime; | ||||
|  | ||||
| @@ -13,6 +16,9 @@ public class PayAppRespVO extends PayAppBaseVO { | ||||
|     @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | ||||
|     private Long id; | ||||
|  | ||||
|     @Schema(description = "应用标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") | ||||
|     private String appKey; | ||||
|  | ||||
|     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||||
|     private LocalDateTime createTime; | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| package cn.iocoder.yudao.module.pay.controller.admin.app.vo; | ||||
|  | ||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||
| import lombok.*; | ||||
| import jakarta.validation.constraints.*; | ||||
| @@ -13,4 +14,8 @@ public class PayAppUpdateReqVO extends PayAppBaseVO { | ||||
|     @NotNull(message = "应用编号不能为空") | ||||
|     private Long id; | ||||
|  | ||||
|     @Schema(description = "应用标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") | ||||
|     @NotNull(message = "应用标识不能为空") | ||||
|     private String appKey; | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -31,6 +31,10 @@ public class PayAppDO extends BaseDO { | ||||
|      */ | ||||
|     @TableId | ||||
|     private Long id; | ||||
|     /** | ||||
|      * 应用标识 | ||||
|      */ | ||||
|     private String appKey; | ||||
|     /** | ||||
|      * 应用名 | ||||
|      */ | ||||
|   | ||||
| @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.pay.dal.mysql.app; | ||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||
| import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||||
| import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | ||||
| import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; | ||||
| import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO; | ||||
| import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; | ||||
| import org.apache.ibatis.annotations.Mapper; | ||||
| @@ -14,9 +13,14 @@ public interface PayAppMapper extends BaseMapperX<PayAppDO> { | ||||
|     default PageResult<PayAppDO> selectPage(PayAppPageReqVO reqVO) { | ||||
|         return selectPage(reqVO, new LambdaQueryWrapperX<PayAppDO>() | ||||
|                 .likeIfPresent(PayAppDO::getName, reqVO.getName()) | ||||
|                 .likeIfPresent(PayAppDO::getAppKey, reqVO.getAppKey()) | ||||
|                 .eqIfPresent(PayAppDO::getStatus, reqVO.getStatus()) | ||||
|                 .betweenIfPresent(PayAppDO::getCreateTime, reqVO.getCreateTime()) | ||||
|                 .orderByDesc(PayAppDO::getId)); | ||||
|     } | ||||
|  | ||||
|     default PayAppDO selectByAppKey(String appKey) { | ||||
|         return selectOne(PayAppDO::getAppKey, appKey); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -7,8 +7,8 @@ import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppCreateReqVO; | ||||
| import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO; | ||||
| import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppUpdateReqVO; | ||||
| import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; | ||||
|  | ||||
| import jakarta.validation.Valid; | ||||
|  | ||||
| import java.util.Collection; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| @@ -88,13 +88,13 @@ public interface PayAppService { | ||||
|      * @return 商户 Map | ||||
|      */ | ||||
|     default Map<Long, PayAppDO> getAppMap(Collection<Long> ids) { | ||||
|         List<PayAppDO> list =  getAppList(ids); | ||||
|         List<PayAppDO> list = getAppList(ids); | ||||
|         return CollectionUtils.convertMap(list, PayAppDO::getId); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 支付应用的合法性 | ||||
|      * | ||||
|      * <p> | ||||
|      * 如果不合法,抛出 {@link ServiceException} 业务异常 | ||||
|      * | ||||
|      * @param id 应用编号 | ||||
| @@ -102,4 +102,14 @@ public interface PayAppService { | ||||
|      */ | ||||
|     PayAppDO validPayApp(Long id); | ||||
|  | ||||
|     /** | ||||
|      * 支付应用的合法性 | ||||
|      * <p> | ||||
|      * 如果不合法,抛出 {@link ServiceException} 业务异常 | ||||
|      * | ||||
|      * @param appKey 应用标识 | ||||
|      * @return 应用 | ||||
|      */ | ||||
|     PayAppDO validPayApp(String appKey); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,9 @@ | ||||
| package cn.iocoder.yudao.module.pay.service.app; | ||||
|  | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||
| import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | ||||
| import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppCreateReqVO; | ||||
| import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO; | ||||
| import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppUpdateReqVO; | ||||
| @@ -11,13 +13,14 @@ import cn.iocoder.yudao.module.pay.dal.mysql.app.PayAppMapper; | ||||
| import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants; | ||||
| import cn.iocoder.yudao.module.pay.service.order.PayOrderService; | ||||
| import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; | ||||
| import jakarta.annotation.Resource; | ||||
| import org.springframework.context.annotation.Lazy; | ||||
| import org.springframework.stereotype.Service; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
|  | ||||
| import jakarta.annotation.Resource; | ||||
| import java.util.Collection; | ||||
| import java.util.List; | ||||
| import java.util.Objects; | ||||
|  | ||||
| import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||
| import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; | ||||
| @@ -43,6 +46,8 @@ public class PayAppServiceImpl implements PayAppService { | ||||
|  | ||||
|     @Override | ||||
|     public Long createApp(PayAppCreateReqVO createReqVO) { | ||||
|         // 验证appKey是否重复 | ||||
|         validateAppKeyDuplicate(null, createReqVO.getAppKey()); | ||||
|         // 插入 | ||||
|         PayAppDO app = PayAppConvert.INSTANCE.convert(createReqVO); | ||||
|         appMapper.insert(app); | ||||
| @@ -54,6 +59,8 @@ public class PayAppServiceImpl implements PayAppService { | ||||
|     public void updateApp(PayAppUpdateReqVO updateReqVO) { | ||||
|         // 校验存在 | ||||
|         validateAppExists(updateReqVO.getId()); | ||||
|         // 验证appKey是否重复 | ||||
|         validateAppKeyDuplicate(updateReqVO.getId(), updateReqVO.getAppKey()); | ||||
|         // 更新 | ||||
|         PayAppDO updateObj = PayAppConvert.INSTANCE.convert(updateReqVO); | ||||
|         appMapper.updateById(updateObj); | ||||
| @@ -101,7 +108,7 @@ public class PayAppServiceImpl implements PayAppService { | ||||
|  | ||||
|     @Override | ||||
|     public List<PayAppDO> getAppList() { | ||||
|          return appMapper.selectList(); | ||||
|         return appMapper.selectList(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
| @@ -110,8 +117,28 @@ public class PayAppServiceImpl implements PayAppService { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public PayAppDO validPayApp(Long id) { | ||||
|         PayAppDO app = appMapper.selectById(id); | ||||
|     public PayAppDO validPayApp(Long appId) { | ||||
|         PayAppDO app = appMapper.selectById(appId); | ||||
|         // 校验支付应用数据是否存在以及可用 | ||||
|         return validatePayAppDO(app); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public PayAppDO validPayApp(String appKey) { | ||||
|         PayAppDO app = appMapper.selectByAppKey(appKey); | ||||
|         // 校验支付应用数据是否存在以及可用 | ||||
|         return validatePayAppDO(app); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 校验支付应用实体的有效性 | ||||
|      * 主要包括存在性检查和禁用状态检查 | ||||
|      * | ||||
|      * @param app 待校验的支付应用实体 | ||||
|      * @return 校验通过的支付应用实体 | ||||
|      * @throws IllegalArgumentException 如果支付应用实体不存在或已被禁用 | ||||
|      */ | ||||
|     private PayAppDO validatePayAppDO(PayAppDO app) { | ||||
|         // 校验是否存在 | ||||
|         if (app == null) { | ||||
|             throw exception(ErrorCodeConstants.APP_NOT_FOUND); | ||||
| @@ -123,4 +150,32 @@ public class PayAppServiceImpl implements PayAppService { | ||||
|         return app; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * 校验应用密钥是否重复 | ||||
|      * 在新增或更新支付应用时,确保应用密钥(appKey)的唯一性 | ||||
|      * 如果是在新增情况下,检查数据库中是否已存在相同的appKey | ||||
|      * 如果是在更新情况下,检查数据库中是否存在除当前应用外的其他应用使用了相同的appKey | ||||
|      * | ||||
|      * @param payAppId  支付应用的ID,更新时使用,新增时可能为null | ||||
|      * @param payAppKey 支付应用的密钥,用于校验是否重复 | ||||
|      * @throws RuntimeException 如果发现appKey重复,抛出运行时异常 | ||||
|      */ | ||||
|     private void validateAppKeyDuplicate(Long payAppId, String payAppKey) { | ||||
|         // 新增时,校验appKey是否重复 | ||||
|         if (Objects.isNull(payAppId) && StrUtil.isNotBlank(payAppKey)) { | ||||
|             if (appMapper.selectCount(PayAppDO::getAppKey, payAppKey) > 0) { | ||||
|                 throw exception(APP_KEY_EXISTS); | ||||
|             } | ||||
|             // 更新时,校验appKey是否重复 | ||||
|         } else if (Objects.nonNull(payAppId) && StrUtil.isNotBlank(payAppKey)) { | ||||
|             LambdaQueryWrapperX<PayAppDO> queryWrapper = new LambdaQueryWrapperX<>(); | ||||
|             queryWrapper.eq(PayAppDO::getAppKey, payAppKey) | ||||
|                     .ne(PayAppDO::getId, payAppId); | ||||
|             if (appMapper.selectCount(queryWrapper) > 0) { | ||||
|                 throw exception(APP_KEY_EXISTS); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -47,7 +47,7 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService { | ||||
|      * | ||||
|      * 从 [支付管理 -> 应用信息] 里添加 | ||||
|      */ | ||||
|     private static final Long PAY_APP_ID = 7L; | ||||
|     private static final String PAY_APP_KEY = "demo"; | ||||
|  | ||||
|     /** | ||||
|      * 商品信息 Map | ||||
| @@ -88,7 +88,7 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService { | ||||
|  | ||||
|         // 2.1 创建支付单 | ||||
|         Long payOrderId = payOrderApi.createOrder(new PayOrderCreateReqDTO() | ||||
|                 .setAppId(PAY_APP_ID).setUserIp(getClientIP()) // 支付应用 | ||||
|                 .setAppKey(PAY_APP_KEY).setUserIp(getClientIP()) // 支付应用 | ||||
|                 .setMerchantOrderId(demoOrder.getId().toString()) // 业务的订单编号 | ||||
|                 .setSubject(spuName).setBody("").setPrice(price) // 价格信息 | ||||
|                 .setExpireTime(addTime(Duration.ofHours(2L)))); // 支付的过期时间 | ||||
| @@ -190,7 +190,7 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService { | ||||
|         String refundId = order.getId() + "-refund"; | ||||
|         // 2.2 创建退款单 | ||||
|         Long payRefundId = payRefundApi.createRefund(new PayRefundCreateReqDTO() | ||||
|                 .setAppId(PAY_APP_ID).setUserIp(getClientIP()) // 支付应用 | ||||
|                 .setAppKey(PAY_APP_KEY).setUserIp(getClientIP()) // 支付应用 | ||||
|                 .setMerchantOrderId(String.valueOf(order.getId())) // 支付单号 | ||||
|                 .setMerchantRefundId(refundId) | ||||
|                 .setReason("想退钱").setPrice(order.getPrice()));// 价格信息 | ||||
|   | ||||
| @@ -111,11 +111,11 @@ public class PayOrderServiceImpl implements PayOrderService { | ||||
|     @Override | ||||
|     public Long createOrder(PayOrderCreateReqDTO reqDTO) { | ||||
|         // 校验 App | ||||
|         PayAppDO app = appService.validPayApp(reqDTO.getAppId()); | ||||
|         PayAppDO app = appService.validPayApp(reqDTO.getAppKey()); | ||||
|  | ||||
|         // 查询对应的支付交易单是否已经存在。如果是,则直接返回 | ||||
|         PayOrderDO order = orderMapper.selectByAppIdAndMerchantOrderId( | ||||
|                 reqDTO.getAppId(), reqDTO.getMerchantOrderId()); | ||||
|                 app.getId(), reqDTO.getMerchantOrderId()); | ||||
|         if (order != null) { | ||||
|             log.warn("[createOrder][appId({}) merchantOrderId({}) 已经存在对应的支付单({})]", order.getAppId(), | ||||
|                     order.getMerchantOrderId(), toJsonString(order)); // 理论来说,不会出现这个情况 | ||||
|   | ||||
| @@ -26,12 +26,12 @@ import cn.iocoder.yudao.module.pay.service.app.PayAppService; | ||||
| import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; | ||||
| import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; | ||||
| import cn.iocoder.yudao.module.pay.service.order.PayOrderService; | ||||
| import jakarta.annotation.Resource; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.springframework.stereotype.Service; | ||||
| import org.springframework.transaction.annotation.Transactional; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
|  | ||||
| import jakarta.annotation.Resource; | ||||
| import java.util.List; | ||||
|  | ||||
| import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||
| @@ -93,9 +93,9 @@ public class PayRefundServiceImpl implements PayRefundService { | ||||
|     @Override | ||||
|     public Long createPayRefund(PayRefundCreateReqDTO reqDTO) { | ||||
|         // 1.1 校验 App | ||||
|         PayAppDO app = appService.validPayApp(reqDTO.getAppId()); | ||||
|         PayAppDO app = appService.validPayApp(reqDTO.getAppKey()); | ||||
|         // 1.2 校验支付订单 | ||||
|         PayOrderDO order = validatePayOrderCanRefund(reqDTO); | ||||
|         PayOrderDO order = validatePayOrderCanRefund(reqDTO, app.getId()); | ||||
|         // 1.3 校验支付渠道是否有效 | ||||
|         PayChannelDO channel = channelService.validPayChannel(order.getChannelId()); | ||||
|         PayClient client = channelService.getPayClient(channel.getId()); | ||||
| @@ -153,8 +153,8 @@ public class PayRefundServiceImpl implements PayRefundService { | ||||
|      * @param reqDTO 退款申请信息 | ||||
|      * @return 支付订单 | ||||
|      */ | ||||
|     private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO) { | ||||
|         PayOrderDO order = orderService.getOrder(reqDTO.getAppId(), reqDTO.getMerchantOrderId()); | ||||
|     private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO, Long appId) { | ||||
|         PayOrderDO order = orderService.getOrder(appId, reqDTO.getMerchantOrderId()); | ||||
|         if (order == null) { | ||||
|             throw exception(PAY_ORDER_NOT_FOUND); | ||||
|         } | ||||
| @@ -164,11 +164,11 @@ public class PayRefundServiceImpl implements PayRefundService { | ||||
|         } | ||||
|  | ||||
|         // 校验金额,退款金额不能大于原定的金额 | ||||
|         if (reqDTO.getPrice() + order.getRefundPrice() > order.getPrice()){ | ||||
|         if (reqDTO.getPrice() + order.getRefundPrice() > order.getPrice()) { | ||||
|             throw exception(REFUND_PRICE_EXCEED); | ||||
|         } | ||||
|         // 是否有退款中的订单 | ||||
|         if (refundMapper.selectCountByAppIdAndOrderId(reqDTO.getAppId(), order.getId(), | ||||
|         if (refundMapper.selectCountByAppIdAndOrderId(appId, order.getId(), | ||||
|                 PayRefundStatusEnum.WAITING.getStatus()) > 0) { | ||||
|             throw exception(REFUND_HAS_REFUNDING); | ||||
|         } | ||||
| @@ -197,9 +197,10 @@ public class PayRefundServiceImpl implements PayRefundService { | ||||
|      * 通知并更新订单的退款结果 | ||||
|      * | ||||
|      * @param channel 支付渠道 | ||||
|      * @param notify 通知 | ||||
|      * @param notify  通知 | ||||
|      */ | ||||
|     @Transactional(rollbackFor = Exception.class)  // 注意,如果是方法内调用该方法,需要通过 getSelf().notifyRefund(channel, notify) 调用,否则事务不生效 | ||||
|     @Transactional(rollbackFor = Exception.class) | ||||
|     // 注意,如果是方法内调用该方法,需要通过 getSelf().notifyRefund(channel, notify) 调用,否则事务不生效 | ||||
|     public void notifyRefund(PayChannelDO channel, PayRefundRespDTO notify) { | ||||
|         // 情况一:退款成功 | ||||
|         if (PayRefundStatusRespEnum.isSuccess(notify.getStatus())) { | ||||
|   | ||||
| @@ -24,12 +24,12 @@ import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum; | ||||
| import cn.iocoder.yudao.module.pay.service.app.PayAppService; | ||||
| import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; | ||||
| import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; | ||||
| import jakarta.annotation.Resource; | ||||
| import jakarta.validation.Validator; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.springframework.stereotype.Service; | ||||
| import org.springframework.transaction.annotation.Transactional; | ||||
|  | ||||
| import jakarta.annotation.Resource; | ||||
| import jakarta.validation.Validator; | ||||
| import java.util.List; | ||||
|  | ||||
| import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||
| @@ -79,16 +79,16 @@ public class PayTransferServiceImpl implements PayTransferService { | ||||
|     @Override | ||||
|     public Long createTransfer(PayTransferCreateReqDTO reqDTO) { | ||||
|         // 1.1 校验 App | ||||
|         PayAppDO payApp = appService.validPayApp(reqDTO.getAppId()); | ||||
|         PayAppDO payApp = appService.validPayApp(reqDTO.getAppKey()); | ||||
|         // 1.2 校验支付渠道是否有效 | ||||
|         PayChannelDO channel = channelService.validPayChannel(reqDTO.getAppId(), reqDTO.getChannelCode()); | ||||
|         PayChannelDO channel = channelService.validPayChannel(payApp.getId(), reqDTO.getChannelCode()); | ||||
|         PayClient client = channelService.getPayClient(channel.getId()); | ||||
|         if (client == null) { | ||||
|             log.error("[createTransfer][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); | ||||
|             throw exception(CHANNEL_NOT_FOUND); | ||||
|         } | ||||
|         // 1.3 校验转账单已经发起过转账。 | ||||
|         PayTransferDO transfer = validateTransferCanCreate(reqDTO); | ||||
|         PayTransferDO transfer = validateTransferCanCreate(reqDTO, payApp.getId()); | ||||
|  | ||||
|         if (transfer == null) { | ||||
|             // 2.不存在创建转账单. 否则允许使用相同的 no 再次发起转账 | ||||
| @@ -116,8 +116,8 @@ public class PayTransferServiceImpl implements PayTransferService { | ||||
|         return transfer.getId(); | ||||
|     } | ||||
|  | ||||
|     private PayTransferDO validateTransferCanCreate(PayTransferCreateReqDTO dto) { | ||||
|         PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(dto.getAppId(), dto.getMerchantTransferId()); | ||||
|     private PayTransferDO validateTransferCanCreate(PayTransferCreateReqDTO dto, Long appId) { | ||||
|         PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(appId, dto.getMerchantTransferId()); | ||||
|         if (transfer != null) { | ||||
|             // 已经存在,并且状态不为等待状态。说明已经调用渠道转账并返回结果. | ||||
|             if (!PayTransferStatusEnum.isWaiting(transfer.getStatus())) { | ||||
|   | ||||
| @@ -54,7 +54,7 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { | ||||
|     /** | ||||
|      * TODO 芋艿:放到 payconfig | ||||
|      */ | ||||
|     private static final Long WALLET_PAY_APP_ID = 8L; | ||||
|     private static final String WALLET_PAY_APP_KEY = "wallet"; | ||||
|  | ||||
|     private static final String WALLET_RECHARGE_ORDER_SUBJECT = "钱包余额充值"; | ||||
|  | ||||
| @@ -92,7 +92,7 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { | ||||
|  | ||||
|         // 2.1 创建支付单 | ||||
|         Long payOrderId = payOrderService.createOrder(new PayOrderCreateReqDTO() | ||||
|                 .setAppId(WALLET_PAY_APP_ID).setUserIp(userIp) | ||||
|                 .setAppKey(WALLET_PAY_APP_KEY).setUserIp(userIp) | ||||
|                 .setMerchantOrderId(recharge.getId().toString()) // 业务的订单编号 | ||||
|                 .setSubject(WALLET_RECHARGE_ORDER_SUBJECT).setBody("") | ||||
|                 .setPrice(recharge.getPayPrice()) | ||||
| @@ -174,7 +174,7 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { | ||||
|         String walletRechargeId = String.valueOf(id); | ||||
|         String refundId = walletRechargeId + "-refund"; | ||||
|         Long payRefundId = payRefundService.createPayRefund(new PayRefundCreateReqDTO() | ||||
|                 .setAppId(WALLET_PAY_APP_ID).setUserIp(userIp) | ||||
|                 .setAppKey(WALLET_PAY_APP_KEY).setUserIp(userIp) | ||||
|                 .setMerchantOrderId(walletRechargeId) | ||||
|                 .setMerchantRefundId(refundId) | ||||
|                 .setReason("想退钱").setPrice(walletRecharge.getPayPrice())); | ||||
|   | ||||
| @@ -218,11 +218,11 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { | ||||
|     public void testCreateOrder_success() { | ||||
|         // mock 参数 | ||||
|         PayOrderCreateReqDTO reqDTO = randomPojo(PayOrderCreateReqDTO.class, | ||||
|                 o -> o.setAppId(1L).setMerchantOrderId("10") | ||||
|                 o -> o.setAppKey("demo").setMerchantOrderId("10") | ||||
|                         .setSubject(randomString()).setBody(randomString())); | ||||
|         // mock 方法 | ||||
|         PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L).setOrderNotifyUrl("http://127.0.0.1")); | ||||
|         when(appService.validPayApp(eq(reqDTO.getAppId()))).thenReturn(app); | ||||
|         when(appService.validPayApp(eq(reqDTO.getAppKey()))).thenReturn(app); | ||||
|  | ||||
|         // 调用 | ||||
|         Long orderId = orderService.createOrder(reqDTO); | ||||
| @@ -239,7 +239,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { | ||||
|     public void testCreateOrder_exists() { | ||||
|         // mock 参数 | ||||
|         PayOrderCreateReqDTO reqDTO = randomPojo(PayOrderCreateReqDTO.class, | ||||
|                 o -> o.setAppId(1L).setMerchantOrderId("10")); | ||||
|                 o -> o.setAppKey("demo").setMerchantOrderId("10")); | ||||
|         // mock 数据 | ||||
|         PayOrderDO dbOrder = randomPojo(PayOrderDO.class,  o -> o.setAppId(1L).setMerchantOrderId("10")); | ||||
|         orderMapper.insert(dbOrder); | ||||
|   | ||||
| @@ -209,7 +209,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { | ||||
|     @Test | ||||
|     public void testCreateRefund_orderNotFound() { | ||||
|         PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, | ||||
|                 o -> o.setAppId(1L)); | ||||
|                 o -> o.setAppKey("demo")); | ||||
|         // mock 方法(app) | ||||
|         PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); | ||||
|         when(appService.validPayApp(eq(1L))).thenReturn(app); | ||||
| @@ -232,7 +232,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { | ||||
|     private void testCreateRefund_orderWaitingOrClosed(Integer status) { | ||||
|         // 准备参数 | ||||
|         PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, | ||||
|                 o -> o.setAppId(1L).setMerchantOrderId("100")); | ||||
|                 o -> o.setAppKey("demo").setMerchantOrderId("100")); | ||||
|         // mock 方法(app) | ||||
|         PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); | ||||
|         when(appService.validPayApp(eq(1L))).thenReturn(app); | ||||
| @@ -249,7 +249,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { | ||||
|     public void testCreateRefund_refundPriceExceed() { | ||||
|         // 准备参数 | ||||
|         PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, | ||||
|                 o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(10)); | ||||
|                 o -> o.setAppKey("demo").setMerchantOrderId("100").setPrice(10)); | ||||
|         // mock 方法(app) | ||||
|         PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); | ||||
|         when(appService.validPayApp(eq(1L))).thenReturn(app); | ||||
| @@ -268,7 +268,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { | ||||
|     public void testCreateRefund_orderHasRefunding() { | ||||
|         // 准备参数 | ||||
|         PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, | ||||
|                 o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(10)); | ||||
|                 o -> o.setAppKey("demo").setMerchantOrderId("100").setPrice(10)); | ||||
|         // mock 方法(app) | ||||
|         PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); | ||||
|         when(appService.validPayApp(eq(1L))).thenReturn(app); | ||||
| @@ -291,7 +291,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { | ||||
|     public void testCreateRefund_channelNotFound() { | ||||
|         // 准备参数 | ||||
|         PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, | ||||
|                 o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(9)); | ||||
|                 o -> o.setAppKey("demo").setMerchantOrderId("100").setPrice(9)); | ||||
|         // mock 方法(app) | ||||
|         PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); | ||||
|         when(appService.validPayApp(eq(1L))).thenReturn(app); | ||||
| @@ -315,7 +315,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { | ||||
|     public void testCreateRefund_refundExists() { | ||||
|         // 准备参数 | ||||
|         PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, | ||||
|                 o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(9) | ||||
|                 o -> o.setAppKey("demo").setMerchantOrderId("100").setPrice(9) | ||||
|                         .setMerchantRefundId("200").setReason("测试退款")); | ||||
|         // mock 方法(app) | ||||
|         PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); | ||||
| @@ -347,7 +347,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { | ||||
|     public void testCreateRefund_invokeException() { | ||||
|         // 准备参数 | ||||
|         PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, | ||||
|                 o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(9) | ||||
|                 o -> o.setAppKey("demo").setMerchantOrderId("100").setPrice(9) | ||||
|                         .setMerchantRefundId("200").setReason("测试退款")); | ||||
|         // mock 方法(app) | ||||
|         PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); | ||||
| @@ -391,7 +391,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { | ||||
|  | ||||
|             // 准备参数 | ||||
|             PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, | ||||
|                     o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(9) | ||||
|                     o -> o.setAppKey("demo").setMerchantOrderId("100").setPrice(9) | ||||
|                             .setMerchantRefundId("200").setReason("测试退款")); | ||||
|             // mock 方法(app) | ||||
|             PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 陈玄礼
					陈玄礼