From 1be40cb19594d49cc4c6fe879138ca5f1b023034 Mon Sep 17 00:00:00 2001 From: YunaiV <> Date: Fri, 26 Apr 2019 22:08:26 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=8E=E7=AB=AF=EF=BC=9A=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E9=83=A8=E5=88=86=E9=80=80=E6=AC=BE=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/users/PayDemoController.java | 99 ----------- .../controller/users/PayRefundController.java | 47 +++++ .../users/PayTransactionController.java | 16 +- .../iocoder/mall/pay/api/PayDemoService.java | 7 - .../mall/pay/api/PayRefundService.java | 23 +++ .../iocoder/mall/pay/api/RefundService.java | 4 - .../mall/pay/api/bo/PayRefundSubmitBO.java | 18 ++ .../pay/api/constant/PayErrorCodeEnum.java | 16 +- .../mall/pay/api/constant/PayNotifyType.java | 44 +++++ .../pay/api/constant/PayRefundStatus.java | 45 +++++ .../constant/PayTransactionStatusEnum.java | 4 +- .../mall/pay/api/dto/PayRefundSubmitDTO.java | 47 +++++ .../pay/api/dto/PayTransactionCreateDTO.java | 2 +- .../api/message/PayRefundSuccessMessage.java | 93 ++++++++++ ...java => PayTransactionSuccessMessage.java} | 18 +- pay/pay-service-impl/pom.xml | 18 ++ .../mall/pay/biz/client/AbstractPaySDK.java | 41 ++++- .../mall/pay/biz/client/PingxxPaySDK.java | 118 +++++++++---- .../mall/pay/biz/client/RefundSuccessBO.java | 34 ++++ .../biz/client/TransactionPaySuccessBO.java | 52 ------ .../pay/biz/client/TransactionSuccessBO.java | 30 ++++ .../pay/biz/component/DubboReferencePool.java | 7 + .../pay/biz/config/XxlJobConfiguration.java | 4 +- .../biz/convert/PayTransactionConvert.java | 23 ++- .../mall/pay/biz/dao/PayRefundMapper.java | 19 ++ .../dao/PayTransactionExtensionMapper.java | 4 +- .../pay/biz/dao/PayTransactionMapper.java | 3 + .../dao/PayTransactionNotifyLogMapper.java | 6 +- .../dao/PayTransactionNotifyTaskMapper.java | 10 +- .../mall/pay/biz/dataobject/PayAppDO.java | 5 + ...onNotifyLogDO.java => PayNotifyLogDO.java} | 4 +- ...NotifyTaskDO.java => PayNotifyTaskDO.java} | 81 +++++++-- .../mall/pay/biz/dataobject/PayRefundDO.java | 92 +++++++++- .../dataobject/PayRepeatTransactionDO.java | 1 + .../pay/biz/dataobject/PayTransactionDO.java | 21 ++- .../dataobject/PayTransactionExtensionDO.java | 2 +- ...ava => PayTransactionSuccessConsumer.java} | 24 +-- .../scheduler/PayTransactionNotifyJob.java | 12 +- .../pay/biz/service/PayDemoServiceImpl.java | 16 -- .../pay/biz/service/PayNotifyServiceImpl.java | 63 +++++++ .../pay/biz/service/PayRefundServiceImpl.java | 165 ++++++++++++++++++ ...pl.java => PayTransactionServiceImpl.java} | 82 +++++---- .../resources/config/application-dev.yaml | 12 ++ .../main/resources/config/application.yaml | 13 -- .../main/resources/mapper/PayAppMapper.xml | 4 +- .../main/resources/mapper/PayRefundMapper.xml | 69 ++++++++ .../mapper/PayTransactionExtensionMapper.xml | 9 +- .../resources/mapper/PayTransactionMapper.xml | 10 +- .../mapper/PayTransactionNotifyLogMapper.xml | 4 +- .../mapper/PayTransactionNotifyTaskMapper.xml | 10 +- 50 files changed, 1180 insertions(+), 371 deletions(-) delete mode 100644 pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/PayDemoController.java create mode 100644 pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/PayRefundController.java delete mode 100644 pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/PayDemoService.java create mode 100644 pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/PayRefundService.java delete mode 100644 pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/RefundService.java create mode 100644 pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/bo/PayRefundSubmitBO.java create mode 100644 pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/constant/PayNotifyType.java create mode 100644 pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/constant/PayRefundStatus.java create mode 100644 pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/dto/PayRefundSubmitDTO.java create mode 100644 pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/message/PayRefundSuccessMessage.java rename pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/message/{PayTransactionPaySuccessMessage.java => PayTransactionSuccessMessage.java} (68%) create mode 100644 pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/client/RefundSuccessBO.java delete mode 100644 pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/client/TransactionPaySuccessBO.java create mode 100644 pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/client/TransactionSuccessBO.java create mode 100644 pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/component/DubboReferencePool.java create mode 100644 pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayRefundMapper.java rename pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/{PayTransactionNotifyLogDO.java => PayNotifyLogDO.java} (87%) rename pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/{PayTransactionNotifyTaskDO.java => PayNotifyTaskDO.java} (53%) rename pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/{PayTransactionPaySuccessConsumer.java => PayTransactionSuccessConsumer.java} (86%) delete mode 100644 pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayDemoServiceImpl.java create mode 100644 pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayNotifyServiceImpl.java create mode 100644 pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayRefundServiceImpl.java rename pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/{PayServiceImpl.java => PayTransactionServiceImpl.java} (73%) create mode 100644 pay/pay-service-impl/src/main/resources/config/application-dev.yaml create mode 100644 pay/pay-service-impl/src/main/resources/mapper/PayRefundMapper.xml diff --git a/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/PayDemoController.java b/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/PayDemoController.java deleted file mode 100644 index 176321c70..000000000 --- a/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/PayDemoController.java +++ /dev/null @@ -1,99 +0,0 @@ -package cn.iocoder.mall.pay.application.controller.users; - -import cn.iocoder.common.framework.util.HttpUtil; -import cn.iocoder.common.framework.vo.CommonResult; -import cn.iocoder.mall.pay.api.PayTransactionService; -import cn.iocoder.mall.pay.api.bo.PayTransactionBO; -import cn.iocoder.mall.pay.api.dto.PayTransactionCreateDTO; -import com.alibaba.dubbo.config.annotation.Reference; -import org.springframework.util.Assert; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.servlet.http.HttpServletRequest; -import java.util.Date; - -/** - * 示例 Controller - */ -@RestController -@RequestMapping("users/demo") -public class PayDemoController { - - @Reference(validation = "true") - private PayTransactionService payTransactionService; - - @PostMapping("/create_order") - public void createOrder(HttpServletRequest request, - @RequestParam("orderId") String orderId) { - // 创建业务订单 - // ... - - // 调用【支付服务】,创建交易订单 - PayTransactionCreateDTO payTransactionCreateDTO = new PayTransactionCreateDTO() - .setAppId("POd4RC6a") - .setCreateIp(HttpUtil.getIp(request)) - .setOrderId(orderId) - .setOrderSubject("商品名" ) - .setOrderDescription("商品描述") - .setOrderMemo("商品备注") - .setPrice(10) - .setExpireTime(new Date()); - CommonResult result = payTransactionService.createTransaction(payTransactionCreateDTO); - Assert.isTrue(result.isSuccess(), "一定会成功的"); - } - - @PostMapping("/pingxx") - public String pingxx() { - return "{\n" + - " \"id\": \"ch_n5COmHGG8iX5TWf5qDynvTaP\",\n" + - " \"object\": \"charge\",\n" + - " \"created\": 1552445643,\n" + - " \"livemode\": false,\n" + - " \"paid\": false,\n" + - " \"refunded\": false,\n" + - " \"reversed\": false,\n" + - " \"app\": \"app_aTyfXDjrvzDSbLuz\",\n" + - " \"channel\": \"wx_pub\",\n" + - " \"order_no\": \"1552445643093\",\n" + - " \"client_ip\": \"127.0.0.1\",\n" + - " \"amount\": 1,\n" + - " \"amount_settle\": 1,\n" + - " \"currency\": \"cny\",\n" + - " \"subject\": \"测试商品\",\n" + - " \"body\": \"测试描述\",\n" + - " \"time_paid\": null,\n" + - " \"time_expire\": 1552452843,\n" + - " \"time_settle\": null,\n" + - " \"transaction_no\": null,\n" + - " \"refunds\": {\n" + - " \"object\": \"list\",\n" + - " \"url\": \"/v1/charges/ch_n5COmHGG8iX5TWf5qDynvTaP/refunds\",\n" + - " \"has_more\": false,\n" + - " \"data\": []\n" + - " },\n" + - " \"amount_refunded\": 0,\n" + - " \"failure_code\": null,\n" + - " \"failure_msg\": null,\n" + - " \"metadata\": {},\n" + - " \"credential\": {\n" + - " \"object\": \"credential\",\n" + - " \"wx_pub\": {\n" + - " \"appId\": \"wxytom5krtuf54qjff\",\n" + - " \"timeStamp\": \"1552445643\",\n" + - " \"nonceStr\": \"5cc0206f78d8bf931980f5132d5ce394\",\n" + - " \"package\": \"prepay_id=1101000000190313rx9y5oahkkcsm5gg\",\n" + - " \"signType\": \"MD5\",\n" + - " \"paySign\": \"9F6E80E89439575B8414FA56ADB07228\"\n" + - " }\n" + - " },\n" + - " \"extra\": {\n" + - " \"open_id\": \"just_for_test\"\n" + - " },\n" + - " \"description\": null\n" + - "}"; - } - -} \ No newline at end of file diff --git a/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/PayRefundController.java b/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/PayRefundController.java new file mode 100644 index 000000000..614b02228 --- /dev/null +++ b/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/PayRefundController.java @@ -0,0 +1,47 @@ +package cn.iocoder.mall.pay.application.controller.users; + +import cn.iocoder.common.framework.vo.CommonResult; +import cn.iocoder.mall.pay.api.PayRefundService; +import cn.iocoder.mall.pay.api.constant.PayChannelEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import java.io.BufferedReader; +import java.io.IOException; + +@RestController +@RequestMapping("users/refund") // TODO 芋艿,理论来说,是用户无关的。这里先酱紫先~ +public class PayRefundController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private PayRefundService payRefundService; + + @PostMapping(value = "pingxx_refund_success", consumes = MediaType.APPLICATION_JSON_VALUE) + public String pingxxRefundSuccess(HttpServletRequest request) throws IOException { + logger.info("[pingxxRefundSuccess][被回调]"); + // 读取 webhook + StringBuilder sb = new StringBuilder(); + try (BufferedReader reader = request.getReader()) { + String line; + while ((line = reader.readLine()) != null) { + sb.append(line); + } + } + + CommonResult result = payRefundService.updateRefundSuccess(PayChannelEnum.PINGXX.getId(), sb.toString()); + if (result.isError()) { + logger.error("[pingxxRefundSuccess][message({}) result({})]", sb, result); + return "failure"; + } + return "success"; + } + +} diff --git a/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/PayTransactionController.java b/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/PayTransactionController.java index 15e247792..fff014ffe 100644 --- a/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/PayTransactionController.java +++ b/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/PayTransactionController.java @@ -25,12 +25,12 @@ public class PayTransactionController { private Logger logger = LoggerFactory.getLogger(getClass()); @Reference(validation = "true") - private PayTransactionService payService; + private PayTransactionService payTransactionService; @GetMapping("/get") public CommonResult get(@RequestParam("appId") String appId, @RequestParam("orderId") String orderId) { - return payService.getTransaction(UserSecurityContextHolder.getContext().getUserId(), appId, orderId); + return payTransactionService.getTransaction(UserSecurityContextHolder.getContext().getUserId(), appId, orderId); } @PostMapping("/submit") // TODO api 注释 @@ -43,13 +43,13 @@ public class PayTransactionController { .setAppId(appId).setOrderId(orderId).setPayChannel(payChannel) .setCreateIp(HttpUtil.getIp(request)); // 提交支付提交 - return payService.submitTransaction(payTransactionSubmitDTO); + return payTransactionService.submitTransaction(payTransactionSubmitDTO); } @PostMapping(value = "pingxx_pay_success", consumes = MediaType.APPLICATION_JSON_VALUE) // @GetMapping(value = "pingxx_pay_success") - public String pingxxSuccess(HttpServletRequest request) throws IOException { - logger.info("[pingxxSuccess][被回调]"); + public String pingxxPaySuccess(HttpServletRequest request) throws IOException { + logger.info("[pingxxPaySuccess][被回调]"); // 读取 webhook StringBuilder sb = new StringBuilder(); try (BufferedReader reader = request.getReader()) { @@ -62,12 +62,12 @@ public class PayTransactionController { // JSONObject bodyObj = JSON.parseObject(sb.toString()); // bodyObj.put("webhookId", bodyObj.remove("id")); // String body = bodyObj.toString(); - CommonResult result = payService.updateTransactionPaySuccess(PayChannelEnum.PINGXX.getId(), sb.toString()); + CommonResult result = payTransactionService.updateTransactionPaySuccess(PayChannelEnum.PINGXX.getId(), sb.toString()); if (result.isError()) { - logger.error("[pingxxSuccess][message({}) result({})]", sb, result); + logger.error("[pingxxPaySuccess][message({}) result({})]", sb, result); return "failure"; } - return result.isSuccess() ? "success" : "failure"; + return "success"; } } diff --git a/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/PayDemoService.java b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/PayDemoService.java deleted file mode 100644 index 77a500cad..000000000 --- a/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/PayDemoService.java +++ /dev/null @@ -1,7 +0,0 @@ -package cn.iocoder.mall.pay.api; - -public interface PayDemoService { - - String updatePaySuccess(String orderId); - -} \ No newline at end of file diff --git a/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/PayRefundService.java b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/PayRefundService.java new file mode 100644 index 000000000..dc56ee4fe --- /dev/null +++ b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/PayRefundService.java @@ -0,0 +1,23 @@ +package cn.iocoder.mall.pay.api; + +import cn.iocoder.common.framework.vo.CommonResult; +import cn.iocoder.mall.pay.api.bo.PayRefundSubmitBO; +import cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO; + +public interface PayRefundService { + + CommonResult submitRefund(PayRefundSubmitDTO payRefundSubmitDTO); + + /** + * 更新退款支付成功 + * + * 该接口用于不同支付平台,退款成功后,回调该接口 + * + * @param payChannel 支付渠道 + * @param params 回调参数。 + * 因为不同平台,能够提供的参数不同,所以使用 String 类型统一接收,然后在使用不同的 AbstractPaySDK 进行处理。 + * @return 是否支付成功 + */ + CommonResult updateRefundSuccess(Integer payChannel, String params); + +} diff --git a/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/RefundService.java b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/RefundService.java deleted file mode 100644 index 7ef7405e7..000000000 --- a/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/RefundService.java +++ /dev/null @@ -1,4 +0,0 @@ -package cn.iocoder.mall.pay.api; - -public interface RefundService { -} diff --git a/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/bo/PayRefundSubmitBO.java b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/bo/PayRefundSubmitBO.java new file mode 100644 index 000000000..f24f2cb2f --- /dev/null +++ b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/bo/PayRefundSubmitBO.java @@ -0,0 +1,18 @@ +package cn.iocoder.mall.pay.api.bo; + +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 退款单结果 BO + */ +@Data +@Accessors(chain = true) +public class PayRefundSubmitBO { + + /** + * 退款 + */ + private Integer id; + +} diff --git a/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/constant/PayErrorCodeEnum.java b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/constant/PayErrorCodeEnum.java index 6a4e0e0ff..76305eb65 100644 --- a/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/constant/PayErrorCodeEnum.java +++ b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/constant/PayErrorCodeEnum.java @@ -11,12 +11,20 @@ public enum PayErrorCodeEnum { PAY_APP_NOT_FOUND(1004000000, "App 不存在"), PAY_APP_IS_DISABLE(1004000001, "App 已经被禁用"), - // ========== TRANSACTION 模块 ========== + // ========== TRANSACTION PAY 模块 ========== PAY_TRANSACTION_NOT_FOUND(100401000, "支付交易单不存在"), PAY_TRANSACTION_STATUS_IS_NOT_WAITING(100401001, "支付交易单不处于待支付"), - PAY_TRANSACTION_EXTENSION_NOT_FOUND(100401002, "支付交易拓展单不存在"), - PAY_TRANSACTION_EXTENSION_STATUS_IS_NOT_WAITING(100401003, "支付交易拓展单不处于待支付"), - PAY_TRANSACTION_ERROR_USER(100401004, "支付交易单用户不正确"), + PAY_TRANSACTION_STATUS_IS_NOT_SUCCESS(100401002, "支付交易单不处于已支付"), + PAY_TRANSACTION_ERROR_USER(100401003, "支付交易单用户不正确"), + + PAY_TRANSACTION_EXTENSION_NOT_FOUND(100401050, "支付交易拓展单不存在"), + PAY_TRANSACTION_EXTENSION_STATUS_IS_NOT_WAITING(100401051, "支付交易拓展单不处于待支付"), + PAY_TRANSACTION_EXTENSION_STATUS_IS_NOT_SUCCESS(100401052, "支付交易单不处于已支付"), + + // ========== TRANSACTION REFUND 模块 ========== + PAY_REFUND_PRICE_EXCEED(100402000, "退款金额超过支付交易单可退金额"), + PAY_REFUND_NOT_FOUND(100402001, "退款单不存在"), + PAY_REFUND_STATUS_NOT_WAITING(100402002, "退款单不处于待处理"), ; private final int code; diff --git a/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/constant/PayNotifyType.java b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/constant/PayNotifyType.java new file mode 100644 index 000000000..fe0876d30 --- /dev/null +++ b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/constant/PayNotifyType.java @@ -0,0 +1,44 @@ +package cn.iocoder.mall.pay.api.constant; + +/** + * 支付通知类型 + */ +public enum PayNotifyType { + + TRANSACTION(1, "支付"), + REFUND(2, "退款"), + ; + + /** + * 类型 + */ + private Integer value; + /** + * 名字 + */ + private String name; + + PayNotifyType(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public PayNotifyType setValue(Integer value) { + this.value = value; + return this; + } + + public String getName() { + return name; + } + + public PayNotifyType setName(String name) { + this.name = name; + return this; + } + +} diff --git a/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/constant/PayRefundStatus.java b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/constant/PayRefundStatus.java new file mode 100644 index 000000000..a68f80010 --- /dev/null +++ b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/constant/PayRefundStatus.java @@ -0,0 +1,45 @@ +package cn.iocoder.mall.pay.api.constant; + +/** + * 支付退款状态枚举 + */ +public enum PayRefundStatus { + + WAITING(1, "处理中"), + SUCCESS(2, "成功"), + FAILURE(3, "失败"), // 例如说,支付单超时 + ; + + /** + * 状态 + */ + private Integer value; + /** + * 名字 + */ + private String name; + + PayRefundStatus(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public PayRefundStatus setValue(Integer value) { + this.value = value; + return this; + } + + public String getName() { + return name; + } + + public PayRefundStatus setName(String name) { + this.name = name; + return this; + } + +} diff --git a/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/constant/PayTransactionStatusEnum.java b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/constant/PayTransactionStatusEnum.java index 9047b1fde..241884271 100644 --- a/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/constant/PayTransactionStatusEnum.java +++ b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/constant/PayTransactionStatusEnum.java @@ -5,7 +5,7 @@ package cn.iocoder.mall.pay.api.constant; */ public enum PayTransactionStatusEnum { - WAITTING(1, "等待支付"), + WAITING(1, "等待支付"), SUCCESS(2, "支付成功"), CANCEL(3, "取消支付"), // 例如说,支付单超时 ; @@ -42,4 +42,4 @@ public enum PayTransactionStatusEnum { return this; } -} \ No newline at end of file +} diff --git a/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/dto/PayRefundSubmitDTO.java b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/dto/PayRefundSubmitDTO.java new file mode 100644 index 000000000..173d7435a --- /dev/null +++ b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/dto/PayRefundSubmitDTO.java @@ -0,0 +1,47 @@ +package cn.iocoder.mall.pay.api.dto; + +import lombok.Data; +import lombok.experimental.Accessors; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * 支付退款创建 DTO + */ +@Data +@Accessors(chain = true) +public class PayRefundSubmitDTO implements Serializable { + + /** + * 应用编号 + */ + @NotEmpty(message = "应用编号不能为空") + private String appId; + /** + * 发起交易的 IP + */ + @NotEmpty(message = "IP 不能为空") + private String createIp; + /** + * 业务线的订单编号 + */ + @NotEmpty(message = "订单号不能为空") + private String orderId; + /** + * 退款描述 + */ + @NotEmpty(message = "退款描述不能为空") + @Length(max = 128, message = "退款描述长度不能超过128") + private String orderDescription; + /** + * 支付金额,单位:分。 + */ + @NotNull(message = "金额不能为空") + @DecimalMin(value = "0", inclusive = false, message = "金额必须大于零") + private Integer price; + +} diff --git a/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/dto/PayTransactionCreateDTO.java b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/dto/PayTransactionCreateDTO.java index ec89b8ec9..857098d4b 100644 --- a/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/dto/PayTransactionCreateDTO.java +++ b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/dto/PayTransactionCreateDTO.java @@ -3,9 +3,9 @@ package cn.iocoder.mall.pay.api.dto; import lombok.Data; import lombok.experimental.Accessors; import org.hibernate.validator.constraints.Length; -import org.hibernate.validator.constraints.NotEmpty; import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import java.io.Serializable; import java.util.Date; diff --git a/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/message/PayRefundSuccessMessage.java b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/message/PayRefundSuccessMessage.java new file mode 100644 index 000000000..200ef7a12 --- /dev/null +++ b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/message/PayRefundSuccessMessage.java @@ -0,0 +1,93 @@ +package cn.iocoder.mall.pay.api.message; + +/** + * 支付退款成功的消息对象 + */ +public class PayRefundSuccessMessage { + + public static final String TOPIC = "PAY_REFUND_SUCCESS"; + + /** + * 任务编号 + */ + private Integer id; + /** + * 退款单编号 + */ + private Integer refundId; + /** + * 交易编号 + */ + private Integer transactionId; + /** + * 应用编号 + */ + private String appId; + /** + * 应用订单编号 + */ + private String orderId; + /** + * 当前通知次数 + */ + private Integer notifyTimes; + /** + * 通知地址 + */ + private String notifyUrl; + + public Integer getId() { + return id; + } + + public PayRefundSuccessMessage setId(Integer id) { + this.id = id; + return this; + } + + public String getAppId() { + return appId; + } + + public PayRefundSuccessMessage setAppId(String appId) { + this.appId = appId; + return this; + } + + public String getOrderId() { + return orderId; + } + + public PayRefundSuccessMessage setOrderId(String orderId) { + this.orderId = orderId; + return this; + } + + public Integer getNotifyTimes() { + return notifyTimes; + } + + public PayRefundSuccessMessage setNotifyTimes(Integer notifyTimes) { + this.notifyTimes = notifyTimes; + return this; + } + + public String getNotifyUrl() { + return notifyUrl; + } + + public PayRefundSuccessMessage setNotifyUrl(String notifyUrl) { + this.notifyUrl = notifyUrl; + return this; + } + + public Integer getTransactionId() { + return transactionId; + } + + public PayRefundSuccessMessage setTransactionId(Integer transactionId) { + this.transactionId = transactionId; + return this; + } + +} diff --git a/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/message/PayTransactionPaySuccessMessage.java b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/message/PayTransactionSuccessMessage.java similarity index 68% rename from pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/message/PayTransactionPaySuccessMessage.java rename to pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/message/PayTransactionSuccessMessage.java index 914f8e91b..190bdfb65 100644 --- a/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/message/PayTransactionPaySuccessMessage.java +++ b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/message/PayTransactionSuccessMessage.java @@ -3,12 +3,12 @@ package cn.iocoder.mall.pay.api.message; /** * 支付交易单支付成功的消息对象 */ -public class PayTransactionPaySuccessMessage { +public class PayTransactionSuccessMessage { - public static final String TOPIC = "PAY_TRANSACTION_PAY_SUCCESS"; + public static final String TOPIC = "PAY_TRANSACTION_SUCCESS"; /** - * 编号,自增 + * 任务编号 */ private Integer id; /** @@ -36,7 +36,7 @@ public class PayTransactionPaySuccessMessage { return id; } - public PayTransactionPaySuccessMessage setId(Integer id) { + public PayTransactionSuccessMessage setId(Integer id) { this.id = id; return this; } @@ -45,7 +45,7 @@ public class PayTransactionPaySuccessMessage { return appId; } - public PayTransactionPaySuccessMessage setAppId(String appId) { + public PayTransactionSuccessMessage setAppId(String appId) { this.appId = appId; return this; } @@ -54,7 +54,7 @@ public class PayTransactionPaySuccessMessage { return orderId; } - public PayTransactionPaySuccessMessage setOrderId(String orderId) { + public PayTransactionSuccessMessage setOrderId(String orderId) { this.orderId = orderId; return this; } @@ -63,7 +63,7 @@ public class PayTransactionPaySuccessMessage { return notifyTimes; } - public PayTransactionPaySuccessMessage setNotifyTimes(Integer notifyTimes) { + public PayTransactionSuccessMessage setNotifyTimes(Integer notifyTimes) { this.notifyTimes = notifyTimes; return this; } @@ -72,7 +72,7 @@ public class PayTransactionPaySuccessMessage { return notifyUrl; } - public PayTransactionPaySuccessMessage setNotifyUrl(String notifyUrl) { + public PayTransactionSuccessMessage setNotifyUrl(String notifyUrl) { this.notifyUrl = notifyUrl; return this; } @@ -81,7 +81,7 @@ public class PayTransactionPaySuccessMessage { return transactionId; } - public PayTransactionPaySuccessMessage setTransactionId(Integer transactionId) { + public PayTransactionSuccessMessage setTransactionId(Integer transactionId) { this.transactionId = transactionId; return this; } diff --git a/pay/pay-service-impl/pom.xml b/pay/pay-service-impl/pom.xml index 1125e7e5f..e15df21fd 100644 --- a/pay/pay-service-impl/pom.xml +++ b/pay/pay-service-impl/pom.xml @@ -63,6 +63,24 @@ rocketmq-spring-boot-starter + + + org.springframework.boot + spring-boot-starter-test + test + + + com.alibaba.boot + dubbo-spring-boot-starter + + + org.apache.curator + curator-framework + + + org.springframework.boot + spring-boot-starter-web + diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/client/AbstractPaySDK.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/client/AbstractPaySDK.java index 1eb738b4e..28f29475e 100644 --- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/client/AbstractPaySDK.java +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/client/AbstractPaySDK.java @@ -1,6 +1,7 @@ package cn.iocoder.mall.pay.biz.client; import cn.iocoder.common.framework.vo.CommonResult; +import cn.iocoder.mall.pay.biz.dataobject.PayRefundDO; import cn.iocoder.mall.pay.biz.dataobject.PayTransactionDO; import cn.iocoder.mall.pay.biz.dataobject.PayTransactionExtensionDO; @@ -8,12 +9,46 @@ import java.util.Map; public abstract class AbstractPaySDK { - // extra 属性,用于支持不同支付平台的拓展字段。例如说,微信公众号支付,需要多传递一个 openid + /** + * 提交支付请求给支付平台,并返回请求结果 + * + * @param transaction 支付交易数据 + * @param transactionExtension 交易扩展数据 + * @param extra 额外参数。用于支持不同支付平台的拓展字段。例如说,微信公众号支付,需要多传递一个 openid + * @return 请求结果 + */ public abstract CommonResult submitTransaction(PayTransactionDO transaction, PayTransactionExtensionDO transactionExtension, Map extra); + /** + * 解析支付成功回调的参数,返回 TransactionSuccessBO 对象 + * + * @param params 回调的参数 + * @return 解析结果 + */ // TODO 芋艿,理论来说不会出现解析失败的情况,先返回这个参数列。等后面封装支付宝和微信支付的时候,在看看。 - public abstract CommonResult parseTransactionPaySuccessParams(String params); + public abstract CommonResult parseTransactionSuccessParams(String params); -} \ No newline at end of file + /** + * 提交退款请求给支付平台,并返回请求结果 + * + * @param refund 退款数据 + * @param transactionExtension 交易扩展数据 + * @param extra 额外参数。用于支持不同支付平台的拓展字段。 + * @return 请求结果 + */ + public abstract CommonResult submitRefund(PayRefundDO refund, + PayTransactionExtensionDO transactionExtension, + Map extra); + + /** + * 解析退款成功回调的参数,返回 RefundSuccessBO 对象 + * + * @param params 回调的参数 + * @return 解析结果 + */ + // TODO 芋艿,理论来说不会出现解析失败的情况,先返回这个参数列。等后面封装支付宝和微信支付的时候,在看看。 + public abstract CommonResult parseRefundSuccessParams(String params); + +} diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/client/PingxxPaySDK.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/client/PingxxPaySDK.java index dd3f57843..4636b4036 100644 --- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/client/PingxxPaySDK.java +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/client/PingxxPaySDK.java @@ -1,6 +1,7 @@ package cn.iocoder.mall.pay.biz.client; import cn.iocoder.common.framework.vo.CommonResult; +import cn.iocoder.mall.pay.biz.dataobject.PayRefundDO; import cn.iocoder.mall.pay.biz.dataobject.PayTransactionDO; import cn.iocoder.mall.pay.biz.dataobject.PayTransactionExtensionDO; import com.alibaba.fastjson.JSON; @@ -9,6 +10,7 @@ import com.google.common.collect.ImmutableMap; import com.pingplusplus.Pingpp; import com.pingplusplus.exception.*; import com.pingplusplus.model.Charge; +import com.pingplusplus.model.Refund; import java.util.Date; import java.util.HashMap; @@ -23,44 +25,29 @@ public class PingxxPaySDK extends AbstractPaySDK { } @Override - public CommonResult submitTransaction(PayTransactionDO transaction, PayTransactionExtensionDO transactionExtension, Map extra) { + public CommonResult submitTransaction(PayTransactionDO transaction, + PayTransactionExtensionDO transactionExtension, + Map extra) { Map reqObj = createChargeRequest(transaction, transactionExtension, extra); // 请求ping++ try { Charge charge = Charge.create(reqObj); System.out.println(charge.toString()); return CommonResult.success(charge.toString()); - } catch (AuthenticationException e) { - e.printStackTrace(); - } catch (InvalidRequestException e) { - e.printStackTrace(); - } catch (APIConnectionException e) { - e.printStackTrace(); - } catch (APIException e) { - e.printStackTrace(); - } catch (ChannelException e) { - e.printStackTrace(); - } catch (RateLimitException e) { + } catch (AuthenticationException | InvalidRequestException | + APIConnectionException | APIException | + ChannelException | RateLimitException e) { e.printStackTrace(); + throw new RuntimeException(e); // TODO 芋艿,后续优化 } - return null; } - @Override - public CommonResult parseTransactionPaySuccessParams(String params) { - JSONObject paramsObj = JSON.parseObject(params); - JSONObject chargeObj = paramsObj.getJSONObject("data").getJSONObject("object"); - TransactionPaySuccessBO transactionPaySuccessBO = new TransactionPaySuccessBO() - .setTransactionCode(chargeObj.getString("order_no")) - .setPaymentTime(new Date(chargeObj.getLong("time_paid") * 1000)) - .setTradeNo(chargeObj.getString("transaction_no")); - return CommonResult.success(transactionPaySuccessBO); - } - - private Map createChargeRequest(PayTransactionDO transaction, PayTransactionExtensionDO transactionExtension, Map extra) { + private static Map createChargeRequest(PayTransactionDO transaction, + PayTransactionExtensionDO transactionExtension, + Map extra) { // 计算支付渠道和支付额外参数 String channel = "wx_pub"; // 因为 ping++ 是用来做模拟支付的渠道,所以这里强制就选择了 wx_pub 微信公众号支付 - extra = new HashMap<>(); // TODO 临时 + extra = new HashMap<>(); // TODO 临时,后面用 extra extra.put("open_id", "just_for_test"); // 生成支付对象 Map reqObj = new HashMap<>(); @@ -77,17 +64,72 @@ public class PingxxPaySDK extends AbstractPaySDK { return reqObj; } - public static void main(String[] args) { - PayTransactionDO transaction = new PayTransactionDO(); - transaction.setOrderSubject("测试商品"); - transaction.setOrderDescription("测试描述"); - transaction.setPrice(1); - - PayTransactionExtensionDO extension = new PayTransactionExtensionDO(); - extension.setTransactionCode(System.currentTimeMillis() + ""); - extension.setCreateIp("127.0.0.1"); - - new PingxxPaySDK().submitTransaction(transaction, extension, null); + @Override + public CommonResult parseTransactionSuccessParams(String params) { + JSONObject paramsObj = JSON.parseObject(params); + JSONObject chargeObj = paramsObj.getJSONObject("data").getJSONObject("object"); + TransactionSuccessBO transactionPaySuccessBO = new TransactionSuccessBO() + .setTransactionCode(chargeObj.getString("order_no")) + .setPaymentTime(new Date(chargeObj.getLong("time_paid") * 1000)) + .setTradeNo(chargeObj.getString("transaction_no")); + return CommonResult.success(transactionPaySuccessBO); } -} \ No newline at end of file + @Override + public CommonResult submitRefund(PayRefundDO refund, + PayTransactionExtensionDO transactionExtension, + Map extra) { + // 解析出 chargeId + JSONObject paramsObj = JSON.parseObject(transactionExtension.getExtensionData()); + JSONObject chargeObj = paramsObj.getJSONObject("data").getJSONObject("object"); + String chargeId = chargeObj.getString("id"); + // 请求ping++ + Map reqObj = createRefundRequest(chargeId, refund.getOrderDescription(), refund.getPrice()); + try { + Refund pingxxRefund = Refund.create(chargeId, reqObj); + System.out.println(pingxxRefund.toString()); + return CommonResult.success(pingxxRefund.toString()); + } catch (AuthenticationException | InvalidRequestException | + APIConnectionException | APIException | + ChannelException | RateLimitException e) { + e.printStackTrace(); + throw new RuntimeException(e); // TODO 芋艿,后续优化 + } + } + + @Override + public CommonResult parseRefundSuccessParams(String params) { + return null; + } + + private Map createRefundRequest(String chargeId, String orderDescription, Integer price) { + Map reqObj = new HashMap<>(); +// reqObj.put("CHARGE_ID", chargeId); + reqObj.put("description", orderDescription); + reqObj.put("amount", price); + return reqObj; + } + + public static void main(String[] args) { + if (false) { // 测试支付请求 + PayTransactionDO transaction = new PayTransactionDO(); + transaction.setOrderSubject("测试商品"); + transaction.setOrderDescription("测试描述"); + transaction.setPrice(1); + + PayTransactionExtensionDO extension = new PayTransactionExtensionDO(); + extension.setTransactionCode(System.currentTimeMillis() + ""); + extension.setCreateIp("127.0.0.1"); + + new PingxxPaySDK().submitTransaction(transaction, extension, null); + } + if (true) { // 测试退款请求 + PayRefundDO refund = new PayRefundDO().setPrice(1).setOrderDescription("测试描述"); + PayTransactionExtensionDO transactionExtension = new PayTransactionExtensionDO() + .setExtensionData("{\"id\":\"evt_400190423100354205607502\",\"created\":1555985033,\"livemode\":false,\"type\":\"charge.succeeded\",\"data\":{\"object\":{\"id\":\"ch_DCGyXTmDGuHKb1C0yTzjPOGC\",\"object\":\"charge\",\"created\":1555985032,\"livemode\":false,\"paid\":true,\"refunded\":false,\"reversed\":false,\"app\":\"app_aTyfXDjrvzDSbLuz\",\"channel\":\"wx_pub\",\"order_no\":\"20190423100352158401\",\"client_ip\":\"114.87.158.59\",\"amount\":10,\"amount_settle\":10,\"currency\":\"cny\",\"subject\":\"kafka 实战\",\"body\":\"测试描述\",\"extra\":{\"open_id\":\"just_for_test\",\"bank_type\":\"your bank type\"},\"time_paid\":1555985033,\"time_expire\":1555992232,\"time_settle\":null,\"transaction_no\":\"1244341374201904238178164740\",\"refunds\":{\"object\":\"list\",\"url\":\"/v1/charges/ch_DCGyXTmDGuHKb1C0yTzjPOGC/refunds\",\"has_more\":false,\"data\":[]},\"amount_refunded\":0,\"failure_code\":null,\"failure_msg\":null,\"metadata\":{},\"credential\":{},\"description\":\"测试备注\"}},\"object\":\"event\",\"request\":\"iar_4e9mPODW5ujPqLen5OOmvL8S\",\"pending_webhooks\":0}"); + + new PingxxPaySDK().submitRefund(refund, transactionExtension, null); + } + } + +} diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/client/RefundSuccessBO.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/client/RefundSuccessBO.java new file mode 100644 index 000000000..64624df22 --- /dev/null +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/client/RefundSuccessBO.java @@ -0,0 +1,34 @@ +package cn.iocoder.mall.pay.biz.client; + +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.Date; + +/** + * 交易退款成功结果 + */ +@Data +@Accessors(chain = true) +public class RefundSuccessBO { + + /** + * 生成传输给第三方的订单号 + * + * 唯一索引 + */ + private String refundCode; + /** + * 第三方的流水号 + */ + private String tradeNo; + /** + * 第三方退款成功的时间 + */ + private Date refundTime; + /** + * 是否成功 + */ + private Boolean success; + +} diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/client/TransactionPaySuccessBO.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/client/TransactionPaySuccessBO.java deleted file mode 100644 index c29e6fa4b..000000000 --- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/client/TransactionPaySuccessBO.java +++ /dev/null @@ -1,52 +0,0 @@ -package cn.iocoder.mall.pay.biz.client; - -import java.util.Date; - -/** - * 交易支付成功结果 - */ -public class TransactionPaySuccessBO { - - /** - * 生成传输给第三方的订单号 - * - * 唯一索引 - */ - private String transactionCode; - /** - * 第三方的流水号 - */ - private String tradeNo; - /** - * 第三方支付成功的时间 - */ - private Date paymentTime; - - public String getTransactionCode() { - return transactionCode; - } - - public TransactionPaySuccessBO setTransactionCode(String transactionCode) { - this.transactionCode = transactionCode; - return this; - } - - public String getTradeNo() { - return tradeNo; - } - - public TransactionPaySuccessBO setTradeNo(String tradeNo) { - this.tradeNo = tradeNo; - return this; - } - - public Date getPaymentTime() { - return paymentTime; - } - - public TransactionPaySuccessBO setPaymentTime(Date paymentTime) { - this.paymentTime = paymentTime; - return this; - } - -} \ No newline at end of file diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/client/TransactionSuccessBO.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/client/TransactionSuccessBO.java new file mode 100644 index 000000000..038791f95 --- /dev/null +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/client/TransactionSuccessBO.java @@ -0,0 +1,30 @@ +package cn.iocoder.mall.pay.biz.client; + +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.Date; + +/** + * 交易支付成功结果 + */ +@Data +@Accessors(chain = true) +public class TransactionSuccessBO { + + /** + * 生成传输给第三方的订单号 + * + * 唯一索引 + */ + private String transactionCode; + /** + * 第三方的流水号 + */ + private String tradeNo; + /** + * 第三方支付成功的时间 + */ + private Date paymentTime; + +} diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/component/DubboReferencePool.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/component/DubboReferencePool.java new file mode 100644 index 000000000..02e6fcd4d --- /dev/null +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/component/DubboReferencePool.java @@ -0,0 +1,7 @@ +package cn.iocoder.mall.pay.biz.component; + +import org.springframework.stereotype.Component; + +@Component +public class DubboReferencePool { +} diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/config/XxlJobConfiguration.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/config/XxlJobConfiguration.java index 5d5c84f9f..df934f473 100644 --- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/config/XxlJobConfiguration.java +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/config/XxlJobConfiguration.java @@ -6,8 +6,10 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; @Configuration +@Profile("dev") public class XxlJobConfiguration { private Logger logger = LoggerFactory.getLogger(XxlJobConfiguration.class); @@ -42,4 +44,4 @@ public class XxlJobConfiguration { return xxlJobSpringExecutor; } -} \ No newline at end of file +} diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/convert/PayTransactionConvert.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/convert/PayTransactionConvert.java index ec6becef8..93c8c64c8 100644 --- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/convert/PayTransactionConvert.java +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/convert/PayTransactionConvert.java @@ -1,13 +1,17 @@ package cn.iocoder.mall.pay.biz.convert; import cn.iocoder.mall.pay.api.bo.PayTransactionBO; +import cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO; import cn.iocoder.mall.pay.api.dto.PayTransactionCreateDTO; import cn.iocoder.mall.pay.api.dto.PayTransactionSubmitDTO; +import cn.iocoder.mall.pay.api.message.PayRefundSuccessMessage; +import cn.iocoder.mall.pay.api.message.PayTransactionSuccessMessage; +import cn.iocoder.mall.pay.biz.dataobject.PayRefundDO; import cn.iocoder.mall.pay.biz.dataobject.PayTransactionDO; import cn.iocoder.mall.pay.biz.dataobject.PayTransactionExtensionDO; -import cn.iocoder.mall.pay.biz.dataobject.PayTransactionNotifyTaskDO; -import cn.iocoder.mall.pay.api.message.PayTransactionPaySuccessMessage; +import cn.iocoder.mall.pay.biz.dataobject.PayNotifyTaskDO; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; import org.mapstruct.Mappings; import org.mapstruct.factory.Mappers; @@ -25,7 +29,20 @@ public interface PayTransactionConvert { @Mappings({}) PayTransactionExtensionDO convert(PayTransactionSubmitDTO payTransactionSubmitDTO); + @Mappings({ + @Mapping(source = "transaction.transactionId", target = "transactionId"), + @Mapping(source = "transaction.orderId", target = "orderId"), + }) + PayTransactionSuccessMessage convert(PayNotifyTaskDO payTransactionNotifyTaskDO); + + @Mappings({ + @Mapping(source = "refund.transactionId", target = "transactionId"), + @Mapping(source = "refund.orderId", target = "orderId"), + @Mapping(source = "refund.refundId", target = "refundId"), + }) + PayRefundSuccessMessage convert2(PayNotifyTaskDO payTransactionNotifyTaskDO); + @Mappings({}) - PayTransactionPaySuccessMessage convert(PayTransactionNotifyTaskDO payTransactionNotifyTaskDO); + PayRefundDO convert(PayRefundSubmitDTO payRefundSubmitDTO); } diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayRefundMapper.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayRefundMapper.java new file mode 100644 index 000000000..745596571 --- /dev/null +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayRefundMapper.java @@ -0,0 +1,19 @@ +package cn.iocoder.mall.pay.biz.dao; + +import cn.iocoder.mall.pay.biz.dataobject.PayRefundDO; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +@Repository +public interface PayRefundMapper { + + void insert(PayRefundDO entity); + + int update(@Param("entity") PayRefundDO entity, + @Param("whereStatus") Integer whereStatus); + + PayRefundDO selectById(@Param("id") Integer id); + + PayRefundDO selectByRefundCode(@Param("refundCode") String refundCode); + +} diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionExtensionMapper.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionExtensionMapper.java index 57608370f..36aeb2172 100644 --- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionExtensionMapper.java +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionExtensionMapper.java @@ -14,4 +14,6 @@ public interface PayTransactionExtensionMapper { PayTransactionExtensionDO selectByTransactionCode(@Param("transactionCode") String transactionCode); -} \ No newline at end of file + PayTransactionExtensionDO selectById(@Param("id") Integer id); + +} diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionMapper.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionMapper.java index 515202513..3c0d40a15 100644 --- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionMapper.java +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionMapper.java @@ -12,6 +12,9 @@ public interface PayTransactionMapper { int update(@Param("entity") PayTransactionDO entity, @Param("whereStatus") Integer whereStatus); + int updateForRefundTotal(@Param("id") Integer id, + @Param("refundTotalIncr") Integer refundTotalIncr); + PayTransactionDO selectByAppIdAndOrderId(@Param("appId") String appId, @Param("orderId") String orderId); diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionNotifyLogMapper.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionNotifyLogMapper.java index c6dd400da..cb9945a91 100644 --- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionNotifyLogMapper.java +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionNotifyLogMapper.java @@ -1,11 +1,11 @@ package cn.iocoder.mall.pay.biz.dao; -import cn.iocoder.mall.pay.biz.dataobject.PayTransactionNotifyLogDO; +import cn.iocoder.mall.pay.biz.dataobject.PayNotifyLogDO; import org.springframework.stereotype.Repository; @Repository public interface PayTransactionNotifyLogMapper { - void insert(PayTransactionNotifyLogDO entity); + void insert(PayNotifyLogDO entity); -} \ No newline at end of file +} diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionNotifyTaskMapper.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionNotifyTaskMapper.java index 3c2462e32..cc6790b8b 100644 --- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionNotifyTaskMapper.java +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionNotifyTaskMapper.java @@ -1,6 +1,6 @@ package cn.iocoder.mall.pay.biz.dao; -import cn.iocoder.mall.pay.biz.dataobject.PayTransactionNotifyTaskDO; +import cn.iocoder.mall.pay.biz.dataobject.PayNotifyTaskDO; import org.springframework.stereotype.Repository; import java.util.List; @@ -8,9 +8,9 @@ import java.util.List; @Repository public interface PayTransactionNotifyTaskMapper { - void insert(PayTransactionNotifyTaskDO entity); + void insert(PayNotifyTaskDO entity); - int update(PayTransactionNotifyTaskDO entity); + int update(PayNotifyTaskDO entity); /** * 获得需要通知的 PayTransactionNotifyTaskDO 记录。需要满足如下条件: @@ -21,6 +21,6 @@ public interface PayTransactionNotifyTaskMapper { * * @return PayTransactionNotifyTaskDO 数组 */ - List selectByNotify(); + List selectByNotify(); -} \ No newline at end of file +} diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayAppDO.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayAppDO.java index b06ce0f24..2ef43c72f 100644 --- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayAppDO.java +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayAppDO.java @@ -21,8 +21,13 @@ public class PayAppDO extends DeletableDO { private String name; /** * 异步通知地址 + * TODO 芋艿,修改成 payNotifyUrl */ private String notifyUrl; + /** + * 退款异步通知地址 + */ + private String refundNotifyUrl; /** * 状态 */ diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionNotifyLogDO.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayNotifyLogDO.java similarity index 87% rename from pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionNotifyLogDO.java rename to pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayNotifyLogDO.java index 9280acd3e..7931d2c07 100644 --- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionNotifyLogDO.java +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayNotifyLogDO.java @@ -5,13 +5,13 @@ import lombok.Data; import lombok.experimental.Accessors; /** - * 支付交易通知 App 的日志 DO + * 支付通知 App 的日志 DO * * 通过该表,记录通知 App 时,产生的日志 */ @Data @Accessors(chain = true) -public class PayTransactionNotifyLogDO extends DeletableDO { +public class PayNotifyLogDO extends DeletableDO { /** * 日志编号,自增 diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionNotifyTaskDO.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayNotifyTaskDO.java similarity index 53% rename from pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionNotifyTaskDO.java rename to pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayNotifyTaskDO.java index 5a3393166..e78c9a589 100644 --- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionNotifyTaskDO.java +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayNotifyTaskDO.java @@ -1,18 +1,20 @@ package cn.iocoder.mall.pay.biz.dataobject; import cn.iocoder.common.framework.dataobject.DeletableDO; -import cn.iocoder.mall.pay.biz.service.PayServiceImpl; +import cn.iocoder.mall.pay.biz.service.PayTransactionServiceImpl; import lombok.Data; import lombok.experimental.Accessors; import java.util.Date; /** - * 支付交易通知 App 的任务 DO + * 支付通知 App 的任务 DO + * + * 目前包括支付通知、退款通知。 */ @Data @Accessors(chain = true) -public class PayTransactionNotifyTaskDO extends DeletableDO { +public class PayNotifyTaskDO extends DeletableDO { /** * 通知频率,单位为秒。 @@ -28,26 +30,16 @@ public class PayTransactionNotifyTaskDO extends DeletableDO { * 编号,自增 */ private Integer id; - /** - * 交易编号 - * - * {@link PayTransactionDO#getId()} - */ - private Integer transactionId; - /** - * 交易拓展编号 - * - * {@link PayTransactionExtensionDO#getId()} - */ - private Integer transactionExtensionId; /** * 应用编号 */ private String appId; /** - * 应用订单编号 + * 类型 + * + * @see cn.iocoder.mall.pay.api.constant.PayNotifyType */ - private String orderId; + private Integer type; /** * 通知状态 * @@ -63,7 +55,7 @@ public class PayTransactionNotifyTaskDO extends DeletableDO { * * 这个字段,需要结合 {@link #nextNotifyTime} 一起使用。 * - * 1. 初始时,{@link PayServiceImpl#updateTransactionPaySuccess(Integer, String)} + * 1. 初始时,{@link PayTransactionServiceImpl#updateTransactionPaySuccess(Integer, String)} * nextNotifyTime 为当前时间 + 15 秒 * lastExecuteTime 为空 * 并发送给 MQ ,执行执行 @@ -87,5 +79,58 @@ public class PayTransactionNotifyTaskDO extends DeletableDO { * 通知地址 */ private String notifyUrl; + // TODO 芋艿,未来把 transaction 和 refund 优化成一个字段。现在为了方便。 + /** + * 支付数据 + */ + private Transaction transaction; + /** + * 退款数据 + */ + private Refund refund; + + @Data + @Accessors(chain = true) + public static class Transaction { + + /** + * 应用订单编号 + */ + private String orderId; + /** + * 交易编号 + * + * {@link PayTransactionDO#getId()} + */ + private Integer transactionId; + /** + * 交易拓展编号 + * + * {@link PayTransactionExtensionDO#getId()} + */ + private Integer transactionExtensionId; + + } + + @Data + @Accessors(chain = true) + public static class Refund { + + /** + * 应用订单编号 + */ + private String orderId; + /** + * 交易编号 + * + * {@link PayTransactionDO#getId()} + */ + private Integer transactionId; + /** + * 退款单编号 + */ + private Integer refundId; + + } } diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayRefundDO.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayRefundDO.java index eea5ce411..e66cec676 100644 --- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayRefundDO.java +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayRefundDO.java @@ -1,9 +1,99 @@ package cn.iocoder.mall.pay.biz.dataobject; +import cn.iocoder.common.framework.dataobject.BaseDO; import lombok.Data; import lombok.experimental.Accessors; +import java.util.Date; + +/** + * 退款单 DO + */ @Data @Accessors(chain = true) -public class PayRefundDO { +public class PayRefundDO extends BaseDO { + + /** + * 编号,自增 + */ + private Integer id; + /** + * 支付交易编号 + */ + private Integer transactionId; + /** + * 生成传输给第三方的退款号 + * + * 唯一索引 + */ + private String refundCode; + /** + * 应用编号 + * + * 不同业务线分配不同的 appId + * 举个例子, + * 1. 电商系统的订单,appId = 1024 + * 2. 活动系统的订单,appId = 2048 + */ + private String appId; + /** + * 业务线的订单编号 + * + * 1. 使用 String 的原因是,业务线可能使用 String 做为编号 + * 2. 每个 appId 下,orderId 唯一 + */ + private String orderId; + /** + * 发起交易的 IP + */ + private String createIp; + /** + * 业务退款描述 + */ + private String orderDescription; + /** + * 退款金额,单位:分。 + * + * TODO 暂时不考虑货币类型。 + */ + private Integer price; + /** + * 退款状态 + * + * @see cn.iocoder.mall.pay.api.constant.PayRefundStatus + */ + private Integer status; + /** + * 回调业务线完成时间 + */ + private Date finishTime; + /** + * 异步通知地址 + */ + private String notifyUrl; + /** + * 扩展内容 + * + * 异步通知的时候填充回调的数据 + */ + private String extensionData; + /** + * 退款渠道 + */ + private Integer refundChannel; + /** + * 第三方退款成功的时间 + */ + private Date refundTime; + /** + * 收到第三方系统通知的时间 + * + * 一般情况下,即第三方系统的异步通知 + */ + private Date notifyTime; + /** + * 第三方的流水号 + */ + private String tradeNo; + } diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayRepeatTransactionDO.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayRepeatTransactionDO.java index eef449846..2452db36b 100644 --- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayRepeatTransactionDO.java +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayRepeatTransactionDO.java @@ -10,5 +10,6 @@ import lombok.experimental.Accessors; */ @Data @Accessors(chain = true) +@Deprecated public class PayRepeatTransactionDO { } diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionDO.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionDO.java index 77159d037..a7eeabb7f 100644 --- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionDO.java +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionDO.java @@ -26,10 +26,6 @@ public class PayTransactionDO extends DeletableDO { * 2. 活动系统的订单,appId = 2048 */ private String appId; - /** - * 发起交易的 IP - */ - private String createIp; /** * 业务线的订单编号 * @@ -37,6 +33,10 @@ public class PayTransactionDO extends DeletableDO { * 2. 每个 appId 下,orderId 唯一 */ private String orderId; + /** + * 发起交易的 IP + */ + private String createIp; /** * 订单商品名 */ @@ -56,7 +56,7 @@ public class PayTransactionDO extends DeletableDO { */ private Integer price; /** - * 订单状态 + * 支付状态 * * @see cn.iocoder.mall.pay.api.constant.PayTransactionStatusEnum */ @@ -69,13 +69,11 @@ public class PayTransactionDO extends DeletableDO { * 回调业务线完成时间 */ private Date finishTime; - - - // TODO return url /** * 异步通知地址 */ private String notifyUrl; + // TODO return url /** * 成功支付的交易拓展编号 @@ -104,4 +102,11 @@ public class PayTransactionDO extends DeletableDO { */ private String tradeNo; + // ========== 退款相关 ========== + + /** + * 退款总金额 + */ + private Integer refundTotal; + } diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionExtensionDO.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionExtensionDO.java index e5f4c6162..f6071043b 100644 --- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionExtensionDO.java +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionExtensionDO.java @@ -43,7 +43,7 @@ public class PayTransactionExtensionDO extends DeletableDO { * 状态 * * @see cn.iocoder.mall.pay.api.constant.PayTransactionStatusEnum - * 注意,只包含上述枚举的 WAITTING 和 SUCCESS + * 注意,只包含上述枚举的 WAITING 和 SUCCESS */ private Integer status; diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/PayTransactionPaySuccessConsumer.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/PayTransactionSuccessConsumer.java similarity index 86% rename from pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/PayTransactionPaySuccessConsumer.java rename to pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/PayTransactionSuccessConsumer.java index e7e0cde70..fc2559524 100644 --- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/PayTransactionPaySuccessConsumer.java +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/PayTransactionSuccessConsumer.java @@ -3,13 +3,13 @@ package cn.iocoder.mall.pay.biz.mq; import cn.iocoder.common.framework.util.DateUtil; import cn.iocoder.common.framework.util.ExceptionUtil; import cn.iocoder.mall.pay.api.constant.PayTransactionNotifyStatusEnum; -import cn.iocoder.mall.pay.api.message.PayTransactionPaySuccessMessage; +import cn.iocoder.mall.pay.api.message.PayTransactionSuccessMessage; import cn.iocoder.mall.pay.biz.dao.PayTransactionMapper; import cn.iocoder.mall.pay.biz.dao.PayTransactionNotifyLogMapper; import cn.iocoder.mall.pay.biz.dao.PayTransactionNotifyTaskMapper; +import cn.iocoder.mall.pay.biz.dataobject.PayNotifyTaskDO; import cn.iocoder.mall.pay.biz.dataobject.PayTransactionDO; -import cn.iocoder.mall.pay.biz.dataobject.PayTransactionNotifyLogDO; -import cn.iocoder.mall.pay.biz.dataobject.PayTransactionNotifyTaskDO; +import cn.iocoder.mall.pay.biz.dataobject.PayNotifyLogDO; import com.alibaba.dubbo.config.ApplicationConfig; import com.alibaba.dubbo.config.ReferenceConfig; import com.alibaba.dubbo.config.RegistryConfig; @@ -31,10 +31,10 @@ import java.util.Date; @Service @RocketMQMessageListener( - topic = PayTransactionPaySuccessMessage.TOPIC, - consumerGroup = "pay-consumer-group-" + PayTransactionPaySuccessMessage.TOPIC + topic = PayTransactionSuccessMessage.TOPIC, + consumerGroup = "pay-consumer-group-" + PayTransactionSuccessMessage.TOPIC ) -public class PayTransactionPaySuccessConsumer implements RocketMQListener { +public class PayTransactionSuccessConsumer implements RocketMQListener { @Data private class ReferenceMeta { @@ -94,7 +94,7 @@ public class PayTransactionPaySuccessConsumer implements RocketMQListener= PayTransactionNotifyTaskDO.NOTIFY_FREQUENCY.length) { + private void handleFailure(PayNotifyTaskDO updateTask, Integer defaultStatus) { + if (updateTask.getNotifyTimes() >= PayNotifyTaskDO.NOTIFY_FREQUENCY.length) { updateTask.setStatus(PayTransactionNotifyStatusEnum.FAILURE.getValue()); } else { - updateTask.setNextNotifyTime(DateUtil.addDate(Calendar.SECOND, PayTransactionNotifyTaskDO.NOTIFY_FREQUENCY[updateTask.getNotifyTimes()])); + updateTask.setNextNotifyTime(DateUtil.addDate(Calendar.SECOND, PayNotifyTaskDO.NOTIFY_FREQUENCY[updateTask.getNotifyTimes()])); updateTask.setStatus(defaultStatus); } } diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/scheduler/PayTransactionNotifyJob.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/scheduler/PayTransactionNotifyJob.java index e3bcc3ac3..b2d26b31a 100644 --- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/scheduler/PayTransactionNotifyJob.java +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/scheduler/PayTransactionNotifyJob.java @@ -1,9 +1,9 @@ package cn.iocoder.mall.pay.biz.scheduler; -import cn.iocoder.mall.pay.api.message.PayTransactionPaySuccessMessage; +import cn.iocoder.mall.pay.api.message.PayTransactionSuccessMessage; import cn.iocoder.mall.pay.biz.convert.PayTransactionConvert; import cn.iocoder.mall.pay.biz.dao.PayTransactionNotifyTaskMapper; -import cn.iocoder.mall.pay.biz.dataobject.PayTransactionNotifyTaskDO; +import cn.iocoder.mall.pay.biz.dataobject.PayNotifyTaskDO; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.IJobHandler; import com.xxl.job.core.handler.annotation.JobHandler; @@ -31,17 +31,17 @@ public class PayTransactionNotifyJob extends IJobHandler { @Override public ReturnT execute(String param) { // 获得需要通知的任务 - List notifyTasks = payTransactionNotifyTaskMapper.selectByNotify(); + List notifyTasks = payTransactionNotifyTaskMapper.selectByNotify(); // 循环任务,发送通知 - for (PayTransactionNotifyTaskDO payTransactionNotifyTask : notifyTasks) { + for (PayNotifyTaskDO payTransactionNotifyTask : notifyTasks) { // 发送 MQ - rocketMQTemplate.convertAndSend(PayTransactionPaySuccessMessage.TOPIC, + rocketMQTemplate.convertAndSend(PayTransactionSuccessMessage.TOPIC, PayTransactionConvert.INSTANCE.convert(payTransactionNotifyTask)); // 更新最后通知时间 // 1. 这样操作,虽然可能会出现 MQ 消费快于下面 PayTransactionNotifyTaskDO 的更新语句。但是,因为更新字段不同,所以不会有问题。 // 2. 换个视角,如果先更新 PayTransactionNotifyTaskDO ,再发送 MQ 消息。如果 MQ 消息发送失败,则 PayTransactionNotifyTaskDO 再也不会被轮询到了。 // 3. 当然,最最最完美的话,就是做事务消息,不过这样又过于复杂~ - PayTransactionNotifyTaskDO updateNotifyTask = new PayTransactionNotifyTaskDO() + PayNotifyTaskDO updateNotifyTask = new PayNotifyTaskDO() .setId(payTransactionNotifyTask.getId()).setLastExecuteTime(new Date()); payTransactionNotifyTaskMapper.update(updateNotifyTask); } diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayDemoServiceImpl.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayDemoServiceImpl.java deleted file mode 100644 index 7a03dc6ca..000000000 --- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayDemoServiceImpl.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.iocoder.mall.pay.biz.service; - -import cn.iocoder.mall.pay.api.PayDemoService; -import org.springframework.stereotype.Service; - -@Service -@com.alibaba.dubbo.config.annotation.Service -public class PayDemoServiceImpl implements PayDemoService { - - @Override - public String updatePaySuccess(String orderId) { -// return "你好呀"; - return "success"; - } - -} \ No newline at end of file diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayNotifyServiceImpl.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayNotifyServiceImpl.java new file mode 100644 index 000000000..e38a21693 --- /dev/null +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayNotifyServiceImpl.java @@ -0,0 +1,63 @@ +package cn.iocoder.mall.pay.biz.service; + +import cn.iocoder.common.framework.util.DateUtil; +import cn.iocoder.mall.pay.api.constant.PayNotifyType; +import cn.iocoder.mall.pay.api.constant.PayTransactionNotifyStatusEnum; +import cn.iocoder.mall.pay.api.message.PayTransactionSuccessMessage; +import cn.iocoder.mall.pay.biz.convert.PayTransactionConvert; +import cn.iocoder.mall.pay.biz.dao.PayTransactionNotifyTaskMapper; +import cn.iocoder.mall.pay.biz.dataobject.PayNotifyTaskDO; +import cn.iocoder.mall.pay.biz.dataobject.PayRefundDO; +import cn.iocoder.mall.pay.biz.dataobject.PayTransactionDO; +import cn.iocoder.mall.pay.biz.dataobject.PayTransactionExtensionDO; +import org.apache.rocketmq.spring.core.RocketMQTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.Calendar; + +@Service +public class PayNotifyServiceImpl { + + @Autowired + private PayTransactionNotifyTaskMapper payTransactionNotifyTaskMapper; + + @Resource + private RocketMQTemplate rocketMQTemplate; + + public void addRefundNotifyTask(PayRefundDO refund) { + PayNotifyTaskDO payTransactionNotifyTask = this.createBasePayNotifyTaskDO(refund.getAppId(), refund.getNotifyUrl()) + .setType(PayNotifyType.REFUND.getValue()); + // 设置 Refund 属性 + payTransactionNotifyTask.setRefund(new PayNotifyTaskDO.Refund().setRefundId(refund.getId()) + .setTransactionId(refund.getTransactionId()).setOrderId(refund.getOrderId())); + // 保存到数据库 + payTransactionNotifyTaskMapper.insert(payTransactionNotifyTask); + // 发送 MQ 消息 + rocketMQTemplate.convertAndSend(PayTransactionSuccessMessage.TOPIC, + PayTransactionConvert.INSTANCE.convert(payTransactionNotifyTask)); + } + + public void addTransactionNotifyTask(PayTransactionDO transaction, PayTransactionExtensionDO extension) { + PayNotifyTaskDO payTransactionNotifyTask = this.createBasePayNotifyTaskDO(transaction.getAppId(), transaction.getNotifyUrl()) + .setType(PayNotifyType.TRANSACTION.getValue()); + // 设置 Transaction 属性 + payTransactionNotifyTask.setTransaction(new PayNotifyTaskDO.Transaction().setOrderId(transaction.getOrderId()) + .setTransactionId(extension.getTransactionId()).setTransactionExtensionId(extension.getId())); + payTransactionNotifyTaskMapper.insert(payTransactionNotifyTask); + // 3.2 发送 MQ + rocketMQTemplate.convertAndSend(PayTransactionSuccessMessage.TOPIC, + PayTransactionConvert.INSTANCE.convert(payTransactionNotifyTask)); + } + + private PayNotifyTaskDO createBasePayNotifyTaskDO(String appId, String notifyUrl) { + return new PayNotifyTaskDO() + .setAppId(appId) + .setStatus(PayTransactionNotifyStatusEnum.WAITING.getValue()) + .setNotifyTimes(0).setMaxNotifyTimes(PayNotifyTaskDO.NOTIFY_FREQUENCY.length + 1) + .setNextNotifyTime(DateUtil.addDate(Calendar.SECOND, PayNotifyTaskDO.NOTIFY_FREQUENCY[0])) + .setNotifyUrl(notifyUrl); + } + +} diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayRefundServiceImpl.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayRefundServiceImpl.java new file mode 100644 index 000000000..15d6ab2d6 --- /dev/null +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayRefundServiceImpl.java @@ -0,0 +1,165 @@ +package cn.iocoder.mall.pay.biz.service; + +import cn.iocoder.common.framework.util.DateUtil; +import cn.iocoder.common.framework.util.MathUtil; +import cn.iocoder.common.framework.util.ServiceExceptionUtil; +import cn.iocoder.common.framework.vo.CommonResult; +import cn.iocoder.mall.pay.api.PayRefundService; +import cn.iocoder.mall.pay.api.bo.PayRefundSubmitBO; +import cn.iocoder.mall.pay.api.constant.*; +import cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO; +import cn.iocoder.mall.pay.biz.client.AbstractPaySDK; +import cn.iocoder.mall.pay.biz.client.PaySDKFactory; +import cn.iocoder.mall.pay.biz.client.RefundSuccessBO; +import cn.iocoder.mall.pay.biz.convert.PayTransactionConvert; +import cn.iocoder.mall.pay.biz.dao.PayRefundMapper; +import cn.iocoder.mall.pay.biz.dataobject.*; +import org.apache.rocketmq.spring.core.RocketMQTemplate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.Date; + +@Service +@com.alibaba.dubbo.config.annotation.Service(validation = "true") +public class PayRefundServiceImpl implements PayRefundService { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private PayRefundMapper payRefundMapper; + + @Autowired + private PayAppServiceImpl payAppService; + @Autowired + private PayNotifyServiceImpl payNotifyService; + @Autowired + private PayTransactionServiceImpl payTransactionService; + + @Resource + private RocketMQTemplate rocketMQTemplate; + + @Override + @SuppressWarnings("Duplicates") + public CommonResult submitRefund(PayRefundSubmitDTO payRefundSubmitDTO) { + // 校验 App 是否有效 + CommonResult appResult = payAppService.validPayApp(payRefundSubmitDTO.getAppId()); + if (appResult.isError()) { + return CommonResult.error(appResult); + } + // 获得 PayTransactionDO ,并校验其是否存在 + PayTransactionDO payTransaction = payTransactionService.getTransaction(payRefundSubmitDTO.getAppId(), payRefundSubmitDTO.getOrderId()); + if (payTransaction == null) { // 是否存在 + return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_NOT_FOUND.getCode()); + } + if (!PayTransactionStatusEnum.SUCCESS.getValue().equals(payTransaction.getStatus())) { // 校验状态,必须是待支付 + return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_STATUS_IS_NOT_SUCCESS.getCode()); + } + if (payRefundSubmitDTO.getPrice() > payTransaction.getPrice() - payTransaction.getRefundTotal()) { // 金额校验 + return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_REFUND_PRICE_EXCEED.getCode()); + } + // 获得 PayTransactionExtensionDO ,并校验其是否存在 + PayTransactionExtensionDO payTransactionExtension = payTransactionService.getPayTransactionExtension(payTransaction.getExtensionId()); + if (payTransactionExtension == null) { // 是否存在 + return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_EXTENSION_NOT_FOUND.getCode()); + } + if (!PayTransactionStatusEnum.SUCCESS.getValue().equals(payTransactionExtension.getStatus())) { // 校验状态,必须是待支付 + return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_EXTENSION_STATUS_IS_NOT_SUCCESS.getCode()); + } + // 插入 PayTransactionExtensionDO + PayRefundDO payRefundDO = PayTransactionConvert.INSTANCE.convert(payRefundSubmitDTO) + .setTransactionId(payTransaction.getId()) + .setRefundCode(generateTransactionCode()) // TODO 芋艿,后续调整 + .setStatus(PayRefundStatus.WAITING.getValue()) + .setNotifyUrl(appResult.getData().getRefundNotifyUrl()) + .setRefundChannel(payTransaction.getPayChannel()); + payRefundDO.setCreateTime(new Date()); + payRefundMapper.insert(payRefundDO); + // 调用三方接口 + AbstractPaySDK paySDK = PaySDKFactory.getSDK(payTransaction.getPayChannel()); + CommonResult invokeResult = paySDK.submitRefund(payRefundDO, payTransactionExtension, null); // TODO 暂时传入 extra = null + if (invokeResult.isError()) { + return CommonResult.error(invokeResult); + } + // 返回成功 + PayRefundSubmitBO payRefundSubmitBO = new PayRefundSubmitBO() + .setId(payRefundDO.getId()); + return CommonResult.success(payRefundSubmitBO); + } + + @Override + @Transactional + public CommonResult updateRefundSuccess(Integer payChannel, String params) { + // TODO 芋艿,记录回调日志 + // 解析传入的参数,成 TransactionSuccessBO 对象 + AbstractPaySDK paySDK = PaySDKFactory.getSDK(payChannel); + CommonResult paySuccessResult = paySDK.parseRefundSuccessParams(params); + if (paySuccessResult.isError()) { + return CommonResult.error(paySuccessResult); + } + // TODO 芋艿,先最严格的校验。即使调用方重复调用,实际哪个订单已经被重复回调的支付,也返回 false 。也没问题,因为实际已经回调成功了。 + // 1.1 查询 PayRefundDO + PayRefundDO payRefund = payRefundMapper.selectByRefundCode(paySuccessResult.getData().getRefundCode()); + if (payRefund == null) { + return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_REFUND_NOT_FOUND.getCode()); + } + if (!PayRefundStatus.WAITING.getValue().equals(payRefund.getStatus())) { // 校验状态,必须是待支付 + return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_REFUND_STATUS_NOT_WAITING.getCode()); + } + // 1.2 更新 PayRefundDO + Integer status = paySuccessResult.getData().getSuccess() ? PayRefundStatus.SUCCESS.getValue() : PayRefundStatus.FAILURE.getValue(); + PayRefundDO updatePayRefundDO = new PayRefundDO() + .setId(payRefund.getId()) + .setStatus(status) + .setExtensionData(params); + int updateCounts = payRefundMapper.update(updatePayRefundDO, PayRefundStatus.WAITING.getValue()); + if (updateCounts == 0) { // 校验状态,必须是待支付 + throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_REFUND_STATUS_NOT_WAITING.getCode()); + } + logger.info("[updateRefundSuccess][PayRefundDO({}) 更新为({})]", payRefund.getId(), status); + // 2.1 判断 PayTransactionDO ,增加已退款金额 + PayTransactionDO payTransaction = payTransactionService.getTransaction(payRefund.getTransactionId()); + if (payTransaction == null) { + return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_NOT_FOUND.getCode()); + } + if (!PayTransactionStatusEnum.SUCCESS.getValue().equals(payTransaction.getStatus())) { // 校验状态,必须是已支付 + throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_STATUS_IS_NOT_SUCCESS.getCode()); + } + if (payRefund.getPrice() + payTransaction.getRefundTotal() > payTransaction.getPrice()) { + throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_REFUND_PRICE_EXCEED.getCode()); + } + // 2.2 更新 PayTransactionDO + updateCounts = payTransactionService.updateTransactionPriceTotalIncr(payRefund.getTransactionId(), payRefund.getPrice()); + if (updateCounts == 0) { // 保证不超退 TODO 这种类型,需要思考下。需要返回错误,但是又要保证事务回滚 + throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_REFUND_PRICE_EXCEED.getCode()); + } + logger.info("[updateRefundSuccess][PayTransactionDO({}) 更新为已支付]", payTransaction.getId()); + // 3 新增 PayNotifyTaskDO + payNotifyService.addRefundNotifyTask(payRefund); + // 返回结果 + return CommonResult.success(true); + } + + private String generateTransactionCode() { +// wx +// 2014 +// 10 +// 27 +// 20 +// 09 +// 39 +// 5522657 +// a690389285100 + // 目前的算法 + // 时间序列,年月日时分秒 14 位 + // 纯随机,6 位 TODO 此处估计是会有问题的,后续在调整 + return DateUtil.format(new Date(), "yyyyMMddHHmmss") + // 时间序列 + MathUtil.random(100000, 999999) // 随机。为什么是这个范围,因为偷懒 + ; + } + +} diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayServiceImpl.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayTransactionServiceImpl.java similarity index 73% rename from pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayServiceImpl.java rename to pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayTransactionServiceImpl.java index 50f6439e3..6e1570488 100644 --- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayServiceImpl.java +++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayTransactionServiceImpl.java @@ -8,14 +8,12 @@ import cn.iocoder.mall.pay.api.PayTransactionService; import cn.iocoder.mall.pay.api.bo.PayTransactionBO; import cn.iocoder.mall.pay.api.bo.PayTransactionSubmitBO; import cn.iocoder.mall.pay.api.constant.PayErrorCodeEnum; -import cn.iocoder.mall.pay.api.constant.PayTransactionNotifyStatusEnum; import cn.iocoder.mall.pay.api.constant.PayTransactionStatusEnum; import cn.iocoder.mall.pay.api.dto.PayTransactionCreateDTO; import cn.iocoder.mall.pay.api.dto.PayTransactionSubmitDTO; -import cn.iocoder.mall.pay.api.message.PayTransactionPaySuccessMessage; import cn.iocoder.mall.pay.biz.client.AbstractPaySDK; import cn.iocoder.mall.pay.biz.client.PaySDKFactory; -import cn.iocoder.mall.pay.biz.client.TransactionPaySuccessBO; +import cn.iocoder.mall.pay.biz.client.TransactionSuccessBO; import cn.iocoder.mall.pay.biz.convert.PayTransactionConvert; import cn.iocoder.mall.pay.biz.dao.PayTransactionExtensionMapper; import cn.iocoder.mall.pay.biz.dao.PayTransactionMapper; @@ -23,21 +21,17 @@ import cn.iocoder.mall.pay.biz.dao.PayTransactionNotifyTaskMapper; import cn.iocoder.mall.pay.biz.dataobject.PayAppDO; import cn.iocoder.mall.pay.biz.dataobject.PayTransactionDO; import cn.iocoder.mall.pay.biz.dataobject.PayTransactionExtensionDO; -import cn.iocoder.mall.pay.biz.dataobject.PayTransactionNotifyTaskDO; -import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import javax.annotation.Resource; -import java.util.Calendar; import java.util.Date; @Service @com.alibaba.dubbo.config.annotation.Service(validation = "true") -public class PayServiceImpl implements PayTransactionService { +public class PayTransactionServiceImpl implements PayTransactionService { private Logger logger = LoggerFactory.getLogger(getClass()); @@ -47,11 +41,27 @@ public class PayServiceImpl implements PayTransactionService { private PayTransactionExtensionMapper payTransactionExtensionMapper; @Autowired private PayTransactionNotifyTaskMapper payTransactionNotifyTaskMapper; + @Autowired private PayAppServiceImpl payAppService; + @Autowired + private PayNotifyServiceImpl payNotifyService; - @Resource - private RocketMQTemplate rocketMQTemplate; + public PayTransactionDO getTransaction(Integer id) { + return payTransactionMapper.selectById(id); + } + + public PayTransactionDO getTransaction(String appId, String orderId) { + return payTransactionMapper.selectByAppIdAndOrderId(appId, orderId); + } + + public int updateTransactionPriceTotalIncr(Integer id, Integer incr) { + return payTransactionMapper.updateForRefundTotal(id, incr); + } + + public PayTransactionExtensionDO getPayTransactionExtension(Integer id) { + return payTransactionExtensionMapper.selectById(id); + } @Override public CommonResult getTransaction(Integer userId, String appId, String orderId) { @@ -80,7 +90,7 @@ public class PayServiceImpl implements PayTransactionService { // TODO 芋艿 可能要考虑,更新订单。例如说,业务线订单可以修改价格 } else { payTransaction = PayTransactionConvert.INSTANCE.convert(payTransactionCreateDTO); - payTransaction.setStatus(PayTransactionStatusEnum.WAITTING.getValue()) + payTransaction.setStatus(PayTransactionStatusEnum.WAITING.getValue()) .setNotifyUrl(appResult.getData().getNotifyUrl()); payTransaction.setCreateTime(new Date()); payTransactionMapper.insert(payTransaction); @@ -104,14 +114,14 @@ public class PayServiceImpl implements PayTransactionService { if (payTransaction == null) { // 是否存在 return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_NOT_FOUND.getCode()); } - if (!PayTransactionStatusEnum.WAITTING.getValue().equals(payTransaction.getStatus())) { // 校验状态,必须是待支付 + if (!PayTransactionStatusEnum.WAITING.getValue().equals(payTransaction.getStatus())) { // 校验状态,必须是待支付 return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_STATUS_IS_NOT_WAITING.getCode()); } // 插入 PayTransactionExtensionDO PayTransactionExtensionDO payTransactionExtensionDO = PayTransactionConvert.INSTANCE.convert(payTransactionSubmitDTO) .setTransactionId(payTransaction.getId()) .setTransactionCode(generateTransactionCode()) - .setStatus(PayTransactionStatusEnum.WAITTING.getValue()); + .setStatus(PayTransactionStatusEnum.WAITING.getValue()); payTransactionExtensionMapper.insert(payTransactionExtensionDO); // 调用三方接口 AbstractPaySDK paySDK = PaySDKFactory.getSDK(payTransactionSubmitDTO.getPayChannel()); @@ -130,67 +140,55 @@ public class PayServiceImpl implements PayTransactionService { @Transactional public CommonResult updateTransactionPaySuccess(Integer payChannel, String params) { // TODO 芋艿,记录回调日志 - // 解析传入的参数,成 TransactionPaySuccessBO 对象 + // 解析传入的参数,成 TransactionSuccessBO 对象 AbstractPaySDK paySDK = PaySDKFactory.getSDK(payChannel); - CommonResult paySuccessResult = paySDK.parseTransactionPaySuccessParams(params); + CommonResult paySuccessResult = paySDK.parseTransactionSuccessParams(params); if (paySuccessResult.isError()) { return CommonResult.error(paySuccessResult); } // TODO 芋艿,先最严格的校验。即使调用方重复调用,实际哪个订单已经被重复回调的支付,也返回 false 。也没问题,因为实际已经回调成功了。 // 1.1 查询 PayTransactionExtensionDO - PayTransactionExtensionDO payTransactionExtension = payTransactionExtensionMapper.selectByTransactionCode(paySuccessResult.getData().getTransactionCode()); - if (payTransactionExtension == null) { + PayTransactionExtensionDO extension = payTransactionExtensionMapper.selectByTransactionCode(paySuccessResult.getData().getTransactionCode()); + if (extension == null) { return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_EXTENSION_NOT_FOUND.getCode()); } - if (!PayTransactionStatusEnum.WAITTING.getValue().equals(payTransactionExtension.getStatus())) { // 校验状态,必须是待支付 + if (!PayTransactionStatusEnum.WAITING.getValue().equals(extension.getStatus())) { // 校验状态,必须是待支付 return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_EXTENSION_STATUS_IS_NOT_WAITING.getCode()); } // 1.2 更新 PayTransactionExtensionDO PayTransactionExtensionDO updatePayTransactionExtension = new PayTransactionExtensionDO() - .setId(payTransactionExtension.getId()) + .setId(extension.getId()) .setStatus(PayTransactionStatusEnum.SUCCESS.getValue()) .setExtensionData(params); - int updateCounts = payTransactionExtensionMapper.update(updatePayTransactionExtension, PayTransactionStatusEnum.WAITTING.getValue()); + int updateCounts = payTransactionExtensionMapper.update(updatePayTransactionExtension, PayTransactionStatusEnum.WAITING.getValue()); if (updateCounts == 0) { // 校验状态,必须是待支付 throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_EXTENSION_STATUS_IS_NOT_WAITING.getCode()); } - logger.info("[updateTransactionPaySuccess][PayTransactionExtensionDO({}) 更新为已支付]", payTransactionExtension.getId()); + logger.info("[updateTransactionPaySuccess][PayTransactionExtensionDO({}) 更新为已支付]", extension.getId()); // 2.1 判断 PayTransactionDO 是否处于待支付 - PayTransactionDO payTransactionDO = payTransactionMapper.selectById(payTransactionExtension.getTransactionId()); - if (payTransactionDO == null) { + PayTransactionDO transaction = payTransactionMapper.selectById(extension.getTransactionId()); + if (transaction == null) { return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_NOT_FOUND.getCode()); } - if (!PayTransactionStatusEnum.WAITTING.getValue().equals(payTransactionDO.getStatus())) { // 校验状态,必须是待支付 + if (!PayTransactionStatusEnum.WAITING.getValue().equals(transaction.getStatus())) { // 校验状态,必须是待支付 throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_STATUS_IS_NOT_WAITING.getCode()); } // 2.2 更新 PayTransactionDO PayTransactionDO updatePayTransaction = new PayTransactionDO() - .setId(payTransactionDO.getId()) + .setId(transaction.getId()) .setStatus(PayTransactionStatusEnum.SUCCESS.getValue()) - .setExtensionId(payTransactionExtension.getId()) + .setExtensionId(extension.getId()) .setPayChannel(payChannel) .setPaymentTime(paySuccessResult.getData().getPaymentTime()) .setNotifyTime(new Date()) .setTradeNo(paySuccessResult.getData().getTradeNo()); - updateCounts = payTransactionMapper.update(updatePayTransaction, PayTransactionStatusEnum.WAITTING.getValue()); + updateCounts = payTransactionMapper.update(updatePayTransaction, PayTransactionStatusEnum.WAITING.getValue()); if (updateCounts == 0) { // 校验状态,必须是待支付 TODO 这种类型,需要思考下。需要返回错误,但是又要保证事务回滚 throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_STATUS_IS_NOT_WAITING.getCode()); } - logger.info("[updateTransactionPaySuccess][PayTransactionDO({}) 更新为已支付]", payTransactionDO.getId()); - // 3.1 插入 - PayTransactionNotifyTaskDO payTransactionNotifyTask = new PayTransactionNotifyTaskDO() - .setTransactionId(payTransactionExtension.getTransactionId()).setTransactionExtensionId(payTransactionExtension.getId()) - .setAppId(payTransactionDO.getAppId()).setOrderId(payTransactionDO.getOrderId()) - .setStatus(PayTransactionNotifyStatusEnum.WAITING.getValue()) - .setNotifyTimes(0).setMaxNotifyTimes(PayTransactionNotifyTaskDO.NOTIFY_FREQUENCY.length + 1) - .setNextNotifyTime(DateUtil.addDate(Calendar.SECOND, PayTransactionNotifyTaskDO.NOTIFY_FREQUENCY[0])) - .setNotifyUrl(payTransactionDO.getNotifyUrl()); - payTransactionNotifyTaskMapper.insert(payTransactionNotifyTask); - logger.info("[updateTransactionPaySuccess][PayTransactionNotifyTaskDO({}) 新增一个任务]", payTransactionNotifyTask.getId()); - // 3.2 发送 MQ - rocketMQTemplate.convertAndSend(PayTransactionPaySuccessMessage.TOPIC, - PayTransactionConvert.INSTANCE.convert(payTransactionNotifyTask)); - logger.info("[updateTransactionPaySuccess][PayTransactionNotifyTaskDO({}) 发送 MQ 任务]", payTransactionNotifyTask.getId()); + logger.info("[updateTransactionPaySuccess][PayTransactionDO({}) 更新为已支付]", transaction.getId()); + // 3 新增 PayNotifyTaskDO + payNotifyService.addTransactionNotifyTask(transaction, extension); // 返回结果 return CommonResult.success(true); } diff --git a/pay/pay-service-impl/src/main/resources/config/application-dev.yaml b/pay/pay-service-impl/src/main/resources/config/application-dev.yaml new file mode 100644 index 000000000..b8ff14095 --- /dev/null +++ b/pay/pay-service-impl/src/main/resources/config/application-dev.yaml @@ -0,0 +1,12 @@ +# xxl-job +xxl: + job: + admin: + addresses: http://127.0.0.1:18079/ + executor: + appname: pay-job-executor + ip: + port: 0 + logpath: /Users/yunai/logs/xxl-job/ + logretentiondays: 1 + accessToken: diff --git a/pay/pay-service-impl/src/main/resources/config/application.yaml b/pay/pay-service-impl/src/main/resources/config/application.yaml index c384b18f2..14146d2bc 100644 --- a/pay/pay-service-impl/src/main/resources/config/application.yaml +++ b/pay/pay-service-impl/src/main/resources/config/application.yaml @@ -24,19 +24,6 @@ dubbo: scan: base-packages: cn.iocoder.mall.pay.biz.service -# xxl-job -xxl: - job: - admin: - addresses: http://127.0.0.1:18079/ - executor: - appname: pay-job-executor - ip: - port: 0 - logpath: /Users/yunai/logs/xxl-job/ - logretentiondays: 1 - accessToken: - # rocketmq rocketmq: name-server: 127.0.0.1:9876 diff --git a/pay/pay-service-impl/src/main/resources/mapper/PayAppMapper.xml b/pay/pay-service-impl/src/main/resources/mapper/PayAppMapper.xml index d5d2758e0..b01ab537e 100644 --- a/pay/pay-service-impl/src/main/resources/mapper/PayAppMapper.xml +++ b/pay/pay-service-impl/src/main/resources/mapper/PayAppMapper.xml @@ -3,7 +3,7 @@ - id, name, notify_url, status, create_time + id, name, notify_url, refund_notify_url, status, create_time @@ -34,4 +34,4 @@ WHERE id = #{id} - \ No newline at end of file + diff --git a/pay/pay-service-impl/src/main/resources/mapper/PayRefundMapper.xml b/pay/pay-service-impl/src/main/resources/mapper/PayRefundMapper.xml new file mode 100644 index 000000000..3f37ae974 --- /dev/null +++ b/pay/pay-service-impl/src/main/resources/mapper/PayRefundMapper.xml @@ -0,0 +1,69 @@ + + + + + + id, transaction_id, refund_cod, app_id, create_ip, order_id, + order_description, price, status, + finish_time, notify_url, extension_data, refund_channel, refund_time, notify_time, + trade_no, create_time + + + + INSERT INTO refund ( + transaction_id, refund_code, app_id, create_ip, order_id, + order_description, price, status, + finish_time, notify_url, extension_data, refund_channel, refund_time, notify_time, + trade_no, create_time + ) VALUES ( + #{transactionId}, #{refundCode}, #{appId}, #{createIp}, #{orderId}, + #{orderDescription}, #{price}, #{status}, + #{finishTime}, #{notifyUrl}, #{extensionData}, #{refundChannel}, #{refundTime}, #{notifyTime}, + #{tradeNo}, #{createTime} + ) + + + + UPDATE refund + + + , status = #{entity.status} + + + , finish_time = #{entity.finishTime} + + + , extension_data = #{entity.extensionData} + + + , refund_time = #{entity.refundTime} + + + , notify_time = #{entity.notifyTime} + + + , trade_no = #{entity.tradeNo} + + + WHERE id = #{entity.id} + + AND status = #{whereStatus} + + + + + + + + diff --git a/pay/pay-service-impl/src/main/resources/mapper/PayTransactionExtensionMapper.xml b/pay/pay-service-impl/src/main/resources/mapper/PayTransactionExtensionMapper.xml index 284b0cbde..489f98e12 100644 --- a/pay/pay-service-impl/src/main/resources/mapper/PayTransactionExtensionMapper.xml +++ b/pay/pay-service-impl/src/main/resources/mapper/PayTransactionExtensionMapper.xml @@ -41,4 +41,11 @@ LIMIT 1 - \ No newline at end of file + + + diff --git a/pay/pay-service-impl/src/main/resources/mapper/PayTransactionMapper.xml b/pay/pay-service-impl/src/main/resources/mapper/PayTransactionMapper.xml index d280d6de3..3a66e0613 100644 --- a/pay/pay-service-impl/src/main/resources/mapper/PayTransactionMapper.xml +++ b/pay/pay-service-impl/src/main/resources/mapper/PayTransactionMapper.xml @@ -6,7 +6,7 @@ id, app_id, create_ip, order_id, order_subject, order_description, order_memo, price, status, expire_time, finish_time, notify_url, extension_id, pay_channel, payment_time, - notify_time, trade_no, create_time + notify_time, trade_no, refund_total, create_time @@ -54,6 +54,12 @@ + + UPDATE `transaction` + SET refundTotal = refundTotal + ${refundTotalIncr} + WHERE price >= refundTotal + ${refundTotalIncr} + + - \ No newline at end of file + diff --git a/pay/pay-service-impl/src/main/resources/mapper/PayTransactionNotifyLogMapper.xml b/pay/pay-service-impl/src/main/resources/mapper/PayTransactionNotifyLogMapper.xml index 6c09d697c..b1794e849 100644 --- a/pay/pay-service-impl/src/main/resources/mapper/PayTransactionNotifyLogMapper.xml +++ b/pay/pay-service-impl/src/main/resources/mapper/PayTransactionNotifyLogMapper.xml @@ -8,7 +8,7 @@ - + INSERT INTO transaction_notify_log ( notify_id, request, response, status ) VALUES ( @@ -43,4 +43,4 @@ - \ No newline at end of file + diff --git a/pay/pay-service-impl/src/main/resources/mapper/PayTransactionNotifyTaskMapper.xml b/pay/pay-service-impl/src/main/resources/mapper/PayTransactionNotifyTaskMapper.xml index 656631c0c..38c2209ce 100644 --- a/pay/pay-service-impl/src/main/resources/mapper/PayTransactionNotifyTaskMapper.xml +++ b/pay/pay-service-impl/src/main/resources/mapper/PayTransactionNotifyTaskMapper.xml @@ -8,7 +8,7 @@ create_time - + INSERT INTO transaction_notify_task ( transaction_id, transaction_extension_id, app_id, order_id, status, next_notify_time, notify_times, max_notify_times @@ -18,7 +18,7 @@ ) - + UPDATE transaction_notify_task @@ -37,13 +37,13 @@ WHERE id = #{id} - SELECT FROM transaction_notify_task - WHERE status IN (1, 3, 4, 5) + WHERE status IN (1, 4, 5) AND next_notify_time NOW() AND last_execute_time > next_notify_time - \ No newline at end of file +