diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java index 3ea29b227..68f36c4bd 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java @@ -2,6 +2,10 @@ package cn.iocoder.yudao.framework.tenant.core.util; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import java.util.Map; + +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; + /** * 多租户 Util * @@ -32,4 +36,16 @@ public class TenantUtils { } } + /** + * 将多租户编号,添加到 header 中 + * + * @param headers HTTP 请求 headers + */ + public static void addTenantHeader(Map headers) { + Long tenantId = TenantContextHolder.getTenantId(); + if (tenantId != null) { + headers.put(HEADER_TENANT_ID, tenantId.toString()); + } + } + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java index 64bd1f5f0..764a88b8b 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderGetCreateInfoRespVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.TradeOrderPageReqVO; @@ -33,7 +34,7 @@ public class AppTradeOrderController { @GetMapping("/get-create-info") @ApiOperation("基于商品,确认创建订单") @PreAuthenticated - public CommonResult getTradeOrderCreateInfo(AppTradeOrderCreateReqVO createReqVO) { + public CommonResult getOrderCreateInfo(AppTradeOrderCreateReqVO createReqVO) { // return success(tradeOrderService.getOrderConfirmCreateInfo(UserSecurityContextHolder.getUserId(), skuId, quantity, couponCardId)); return null; } @@ -41,8 +42,8 @@ public class AppTradeOrderController { @PostMapping("/create") @ApiOperation("创建订单") @PreAuthenticated - public CommonResult createTradeOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO, - HttpServletRequest servletRequest) { + public CommonResult createOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO, + HttpServletRequest servletRequest) { // 获取登录用户、用户 IP 地址 Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); String clientIp = ServletUtil.getClientIP(servletRequest); @@ -51,6 +52,12 @@ public class AppTradeOrderController { return CommonResult.success(orderId); } + @PostMapping("/update-paid") + @ApiOperation(value = "更新订单为已支付", notes = "由 pay-module 支付服务,进行回调,可见 PayNotifyJob") + public CommonResult updateOrderPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) { + return null; + } + @GetMapping("/get") @ApiOperation("获得交易订单") @ApiImplicitParam(name = "tradeOrderId", value = "交易订单编号", required = true, dataTypeClass = Long.class) diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayOrderNotifyReqDTO.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayOrderNotifyReqDTO.java new file mode 100644 index 000000000..8920884ff --- /dev/null +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayOrderNotifyReqDTO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.pay.api.notify.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 支付单的通知 Request DTO + * + * @author 芋道源码 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PayOrderNotifyReqDTO { + + /** + * 商户订单编号 + */ + @NotEmpty(message = "商户订单号不能为空") + private String merchantOrderId; + + /** + * 支付订单编号 + */ + @NotNull(message = "支付订单编号不能为空") + private Long payOrderId; + +} diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayRefundNotifyReqDTO.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayRefundNotifyReqDTO.java new file mode 100644 index 000000000..879854264 --- /dev/null +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayRefundNotifyReqDTO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.pay.api.notify.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 退款单的通知 Request DTO + * + * @author 芋道源码 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PayRefundNotifyReqDTO { + + /** + * 商户退款单编号 + */ + @NotEmpty(message = "商户退款单编号不能为空") + private String merchantOrderId; + + /** + * 支付退款编号 + */ + @NotNull(message = "支付退款编号不能为空") + private Long payRefundId; + + /** + * 退款状态 + * + * (成功,失败) TODO 芋艿:枚举 + */ + @NotNull(message = "退款状态不能为空") + private Integer status; + +} diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/package-info.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/package-info.java new file mode 100644 index 000000000..60c4ca883 --- /dev/null +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位符,无特殊作用 + */ +package cn.iocoder.yudao.module.pay.api.notify; diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/notify/PayNotifyJob.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/notify/PayNotifyJob.java index fab0c8143..2907b75f3 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/notify/PayNotifyJob.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/notify/PayNotifyJob.java @@ -15,8 +15,8 @@ import javax.annotation.Resource; * @author 芋道源码 */ @Component +@TenantJob // 多租户 @Slf4j -@TenantJob public class PayNotifyJob implements JobHandler { @Resource diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/package-info.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/package-info.java index 1421e4e65..40ab66da0 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/package-info.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/package-info.java @@ -2,8 +2,8 @@ * pay 模块,我们放支付业务,提供业务的支付能力。 * 例如说:商户、应用、支付、退款等等 * - * 1. Controller URL:以 /member/ 开头,避免和其它 Module 冲突 - * 2. DataObject 表名:以 member_ 开头,方便在数据库中区分 + * 1. Controller URL:以 /pay/ 开头,避免和其它 Module 冲突 + * 2. DataObject 表名:以 pay_ 开头,方便在数据库中区分 * * 注意,由于 Pay 模块和 Trade 模块,容易重名,所以类名都加载 Pay 的前缀~ */ diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java index bc941b06d..2de48cba3 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java @@ -2,7 +2,13 @@ package cn.iocoder.yudao.module.pay.service.notify; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.exceptions.ExceptionUtil; +import cn.hutool.http.HttpResponse; import cn.hutool.http.HttpUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO; import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; @@ -13,11 +19,8 @@ import cn.iocoder.yudao.module.pay.dal.redis.notify.PayNotifyLockRedisDAO; import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum; import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO; -import cn.iocoder.yudao.module.pay.service.notify.vo.PayNotifyOrderReqVO; -import cn.iocoder.yudao.module.pay.service.notify.vo.PayRefundOrderReqVO; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.util.date.DateUtils; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; +import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO; import cn.iocoder.yudao.module.pay.service.order.PayOrderService; import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; import lombok.extern.slf4j.Slf4j; @@ -30,7 +33,9 @@ import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import javax.validation.Valid; import java.time.LocalDateTime; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -164,8 +169,9 @@ public class PayNotifyServiceImpl implements PayNotifyService { // 校验,当前任务是否已经被通知过 // 虽然已经通过分布式加锁,但是可能同时满足通知的条件,然后都去获得锁。此时,第一个执行完后,第二个还是能拿到锁,然后会再执行一次。 PayNotifyTaskDO dbTask = payNotifyTaskCoreMapper.selectById(task.getId()); - if (DateUtils.afterNow(dbTask.getNextNotifyTime())) { - log.info("[executeNotify][dbTask({}) 任务被忽略,原因是未到达下次通知时间,可能是因为并发执行了]", JsonUtils.toJsonString(dbTask)); + if (LocalDateTimeUtils.afterNow(dbTask.getNextNotifyTime())) { + log.info("[executeNotifySync][dbTask({}) 任务被忽略,原因是未到达下次通知时间,可能是因为并发执行了]", + JsonUtils.toJsonString(dbTask)); return; } @@ -185,11 +191,12 @@ public class PayNotifyServiceImpl implements PayNotifyService { invokeException = e; } - // 处理 - Integer newStatus = this.processNotifyResult(task, invokeResult, invokeException); + // 处理结果 + Integer newStatus = processNotifyResult(task, invokeResult, invokeException); // 记录 PayNotifyLog 日志 - String response = invokeException != null ? ExceptionUtil.getRootCauseMessage(invokeException) : JsonUtils.toJsonString(invokeResult); + String response = invokeException != null ? ExceptionUtil.getRootCauseMessage(invokeException) : + JsonUtils.toJsonString(invokeResult); payNotifyLogCoreMapper.insert(PayNotifyLogDO.builder().taskId(task.getId()) .notifyTimes(task.getNotifyTimes() + 1).status(newStatus).response(response).build()); } @@ -201,22 +208,28 @@ public class PayNotifyServiceImpl implements PayNotifyService { * @return HTTP 响应 */ private CommonResult executeNotifyInvoke(PayNotifyTaskDO task) { - // 拼接参数 + // 拼接 body 参数 Object request; if (Objects.equals(task.getType(), PayNotifyTypeEnum.ORDER.getType())) { - request = PayNotifyOrderReqVO.builder().merchantOrderId(task.getMerchantOrderId()) + request = PayOrderNotifyReqDTO.builder().merchantOrderId(task.getMerchantOrderId()) .payOrderId(task.getDataId()).build(); } else if (Objects.equals(task.getType(), PayNotifyTypeEnum.REFUND.getType())) { - request = PayRefundOrderReqVO.builder().merchantOrderId(task.getMerchantOrderId()) + request = PayRefundNotifyReqDTO.builder().merchantOrderId(task.getMerchantOrderId()) .payRefundId(task.getDataId()).build(); } else { throw new RuntimeException("未知的通知任务类型:" + JsonUtils.toJsonString(task)); } - // 请求地址 - String response = HttpUtil.post(task.getNotifyUrl(), JsonUtils.toJsonString(request), - (int) NOTIFY_TIMEOUT_MILLIS); - // 解析结果 - return JsonUtils.parseObject(response, CommonResult.class); + // 拼接 header 参数 + Map headers = new HashMap<>(); + TenantUtils.addTenantHeader(headers); + + // 发起请求 + try (HttpResponse response = HttpUtil.createPost(task.getNotifyUrl()) + .body(JsonUtils.toJsonString(request)).addHeaders(headers) + .timeout((int) NOTIFY_TIMEOUT_MILLIS).execute()) { + // 解析结果 + return JsonUtils.parseObject(response.body(), CommonResult.class); + } } /** diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/PayNotifyOrderReqVO.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/PayNotifyOrderReqVO.java deleted file mode 100644 index d4f6c1eae..000000000 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/PayNotifyOrderReqVO.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.iocoder.yudao.module.pay.service.notify.vo; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - -@ApiModel(value = "支付单的通知 Request VO", description = "业务方接入支付回调时,使用该 VO 对象") -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class PayNotifyOrderReqVO { - - @ApiModelProperty(value = "商户订单编号", required = true, example = "10") - @NotEmpty(message = "商户订单号不能为空") - private String merchantOrderId; - - @ApiModelProperty(value = "支付订单编号", required = true, example = "20") - @NotNull(message = "支付订单编号不能为空") - private Long payOrderId; - -} diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/PayRefundOrderReqVO.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/PayRefundOrderReqVO.java deleted file mode 100644 index 978283d1b..000000000 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/PayRefundOrderReqVO.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.iocoder.yudao.module.pay.service.notify.vo; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - -@ApiModel(value = "退款单的通知 Request VO", description = "业务方接入退款回调时,使用该 VO 对象") -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class PayRefundOrderReqVO { - - @ApiModelProperty(value = "商户退款单编号", required = true, example = "10") - @NotEmpty(message = "商户退款单编号不能为空") - private String merchantOrderId; - - @ApiModelProperty(value = "支付退款编号", required = true, example = "20") - @NotNull(message = "支付退款编号不能为空") - private Long payRefundId; - - @ApiModelProperty(value = "退款状态(成功,失败)", required = true, example = "10") - private Integer status; - -} diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/package-info.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/package-info.java deleted file mode 100644 index fb006dd68..000000000 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -/** - * 这里的 VO 包有点特殊,是提供给接入支付模块的业务,提供回调接口时,可以直接使用 VO - * - * 例如说,支付单的回调,使用 TODO 芋艿:想下怎么优化下 - */ -package cn.iocoder.yudao.module.pay.service.notify.vo; diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/package-info.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/package-info.java deleted file mode 100644 index 2cad91eba..000000000 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.module.pay.service; diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/module/shop/controller/app/AppShopOrderController.java b/yudao-server/src/main/java/cn/iocoder/yudao/module/shop/controller/app/AppShopOrderController.java index 5a6f42de8..9e66b17a4 100644 --- a/yudao-server/src/main/java/cn/iocoder/yudao/module/shop/controller/app/AppShopOrderController.java +++ b/yudao-server/src/main/java/cn/iocoder/yudao/module/shop/controller/app/AppShopOrderController.java @@ -1,8 +1,8 @@ package cn.iocoder.yudao.module.shop.controller.app; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.pay.service.notify.vo.PayNotifyOrderReqVO; -import cn.iocoder.yudao.module.pay.service.notify.vo.PayRefundOrderReqVO; +import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; +import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO; import cn.iocoder.yudao.module.pay.service.order.PayOrderService; import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; import cn.iocoder.yudao.module.pay.util.PaySeqUtils; @@ -58,14 +58,14 @@ public class AppShopOrderController { @PostMapping("/pay-notify") @ApiOperation("支付回调") - public CommonResult payNotify(@RequestBody @Valid PayNotifyOrderReqVO reqVO) { + public CommonResult payNotify(@RequestBody @Valid PayOrderNotifyReqDTO reqVO) { log.info("[payNotify][回调成功]"); return success(true); } @PostMapping("/refund-notify") @ApiOperation("退款回调") - public CommonResult refundNotify(@RequestBody @Valid PayRefundOrderReqVO reqVO) { + public CommonResult refundNotify(@RequestBody @Valid PayRefundNotifyReqDTO reqVO) { log.info("[refundNotify][回调成功]"); return success(true); }