From 63b4c27c8f3403d2920379de2711300d8cacdd64 Mon Sep 17 00:00:00 2001 From: YunaiV <> Date: Mon, 30 Nov 2020 01:07:28 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=20pingxx=20=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E5=9B=9E=E8=B0=83=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mall/pay/api/PayTransactionService.java | 12 --- .../mall/pay/api/constant/PayNotifyType.java | 44 ----------- .../PayTransactionNotifyStatusEnum.java | 38 ---------- .../users/UsersPayRefundController.java | 47 ------------ .../pay/biz/convert/PayNotifyConvert.java | 29 ------- .../mall/pay/biz/dao/PayNotifyLogMapper.java | 11 --- .../mall/pay/biz/dao/PayNotifyTaskMapper.java | 26 ------- .../pay/biz/dao/PayTransactionMapper.java | 3 - .../pay/biz/service/PayNotifyServiceImpl.java | 75 ------------------- .../service/PayTransactionServiceImpl.java | 57 -------------- .../resources/mapper/PayNotifyLogMapper.xml | 46 ------------ .../resources/mapper/PayNotifyTaskMapper.xml | 61 --------------- .../mapper/PayTransactionExtensionMapper.xml | 26 ------- .../enums/notify/PayNotifyStatusEnum.java | 33 ++++++++ .../enums/notify/PayNotifyType.java | 29 +++++++ .../transaction/PayTransactionStatusEnum.java | 29 ++----- .../rpc/transaction/PayTransactionRpc.java | 8 ++ .../dto/PayTransactionGetReqDTO.java | 3 +- .../dto/PayTransactionRespDTO.java | 3 +- .../dto/PayTransactionSubmitReqDTO.java | 3 +- .../dto/PayTransactionSubmitRespDTO.java | 4 +- .../dto/PayTransactionSuccessReqDTO.java | 24 ++++++ pay-service-project/pay-service-app/pom.xml | 6 ++ .../convert/notify/PayNotifyConvert.java | 18 +++++ .../dal/mysql/dataobject/log}/PayLogDO.java | 2 +- .../dataobject/notify}/PayNotifyLogDO.java | 11 ++- .../dataobject/notify}/PayNotifyTaskDO.java | 24 ++++-- .../mapper/notify/PayNotifyLogMapper.java | 10 +++ .../mapper/notify/PayNotifyTaskMapper.java | 41 ++++++++++ .../transaction/PayTransactionMapper.java | 5 ++ .../payservice/mq/producer/PayMQProducer.java | 45 +++++++++++ .../AbstractPayNotifySuccessMessage.java | 2 +- .../message/PayRefundSuccessMessage.java | 4 +- .../message/PayTransactionSuccessMessage.java | 4 +- .../transaction/PayTransactionRpcImpl.java | 6 ++ .../service/notify/PayNotifyService.java | 18 +++++ .../notify/impl/PayNotifyServiceImpl.java | 70 +++++++++++++++++ .../transaction/PayTransactionService.java | 12 +++ .../impl/PayTransactionServiceImpl.java | 72 ++++++++++++++++-- .../client/pay/PayTransactionClient.java | 11 ++- .../pay/PayTransactionController.java | 45 ++++++----- .../service/pay/PayTransactionService.java | 6 +- 42 files changed, 480 insertions(+), 543 deletions(-) delete mode 100644 moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api/constant/PayNotifyType.java delete mode 100644 moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api/constant/PayTransactionNotifyStatusEnum.java delete mode 100644 moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/UsersPayRefundController.java delete mode 100644 moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/convert/PayNotifyConvert.java delete mode 100644 moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/dao/PayNotifyLogMapper.java delete mode 100644 moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/dao/PayNotifyTaskMapper.java delete mode 100644 moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/service/PayNotifyServiceImpl.java delete mode 100644 moved/pay/pay-application/src/main/resources/mapper/PayNotifyLogMapper.xml delete mode 100644 moved/pay/pay-application/src/main/resources/mapper/PayNotifyTaskMapper.xml create mode 100644 pay-service-project/pay-service-api/src/main/java/cn/iocoder/mall/payservice/enums/notify/PayNotifyStatusEnum.java create mode 100644 pay-service-project/pay-service-api/src/main/java/cn/iocoder/mall/payservice/enums/notify/PayNotifyType.java create mode 100644 pay-service-project/pay-service-api/src/main/java/cn/iocoder/mall/payservice/rpc/transaction/dto/PayTransactionSuccessReqDTO.java create mode 100644 pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/convert/notify/PayNotifyConvert.java rename {moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/dataobject => pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/dal/mysql/dataobject/log}/PayLogDO.java (87%) rename {moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/dataobject => pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/dal/mysql/dataobject/notify}/PayNotifyLogDO.java (59%) rename {moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/dataobject => pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/dal/mysql/dataobject/notify}/PayNotifyTaskDO.java (72%) create mode 100644 pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/dal/mysql/mapper/notify/PayNotifyLogMapper.java create mode 100644 pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/dal/mysql/mapper/notify/PayNotifyTaskMapper.java create mode 100644 pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/mq/producer/PayMQProducer.java rename {moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api => pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/mq/producer}/message/AbstractPayNotifySuccessMessage.java (87%) rename {moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api => pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/mq/producer}/message/PayRefundSuccessMessage.java (79%) rename {moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api => pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/mq/producer}/message/PayTransactionSuccessMessage.java (77%) create mode 100644 pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/service/notify/PayNotifyService.java create mode 100644 pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/service/notify/impl/PayNotifyServiceImpl.java diff --git a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api/PayTransactionService.java b/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api/PayTransactionService.java index 22e9b5f23..47852f4ba 100644 --- a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api/PayTransactionService.java +++ b/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api/PayTransactionService.java @@ -14,18 +14,6 @@ import java.util.List; public interface PayTransactionService { - /** - * 更新交易支付成功 - * - * 该接口用于不同支付平台,支付成功后,回调该接口 - * - * @param payChannel 支付渠道 - * @param params 回调参数。 - * 因为不同平台,能够提供的参数不同,所以使用 String 类型统一接收,然后在使用不同的 AbstractPaySDK 进行处理。 - * @return 是否支付成功 - */ - Boolean updateTransactionPaySuccess(Integer payChannel, String params); - List getTransactionList(Collection ids); PayTransactionPageBO getTransactionPage(PayTransactionPageDTO payTransactionPageDTO); diff --git a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api/constant/PayNotifyType.java b/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api/constant/PayNotifyType.java deleted file mode 100644 index fe0876d30..000000000 --- a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api/constant/PayNotifyType.java +++ /dev/null @@ -1,44 +0,0 @@ -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/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api/constant/PayTransactionNotifyStatusEnum.java b/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api/constant/PayTransactionNotifyStatusEnum.java deleted file mode 100644 index 0d85e7efa..000000000 --- a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api/constant/PayTransactionNotifyStatusEnum.java +++ /dev/null @@ -1,38 +0,0 @@ -package cn.iocoder.mall.pay.api.constant; - -/** - * 支付交易通知状态枚举 - */ -public enum PayTransactionNotifyStatusEnum { - - WAITING(1, "等待通知"), - SUCCESS(2, "通知成功"), - FAILURE(3, "通知失败"), // 多次尝试,彻底失败 - REQUEST_SUCCESS(4, "请求成功,但是结果失败"), - REQUEST_FAILURE(5, "请求失败"), - - ; - - /** - * 状态 - */ - private Integer value; - /** - * 名字 - */ - private String name; - - PayTransactionNotifyStatusEnum(Integer value, String name) { - this.value = value; - this.name = name; - } - - public Integer getValue() { - return value; - } - - public String getName() { - return name; - } - -} \ No newline at end of file diff --git a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/UsersPayRefundController.java b/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/UsersPayRefundController.java deleted file mode 100644 index e83162b22..000000000 --- a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/UsersPayRefundController.java +++ /dev/null @@ -1,47 +0,0 @@ -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.apache.dubbo.config.annotation.Reference; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -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 UsersPayRefundController { - - private Logger logger = LoggerFactory.getLogger(getClass()); - - @Reference(validation = "true", version = "${dubbo.provider.PayRefundService.version}") - 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/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/convert/PayNotifyConvert.java b/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/convert/PayNotifyConvert.java deleted file mode 100644 index 473601d8f..000000000 --- a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/convert/PayNotifyConvert.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.iocoder.mall.pay.biz.convert; - -import cn.iocoder.mall.pay.api.message.PayRefundSuccessMessage; -import cn.iocoder.mall.pay.api.message.PayTransactionSuccessMessage; -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; - -@Mapper -public interface PayNotifyConvert { - - PayNotifyConvert INSTANCE = Mappers.getMapper(PayNotifyConvert.class); - - @Mappings({ - @Mapping(source = "transaction.transactionId", target = "transactionId"), - @Mapping(source = "transaction.orderId", target = "orderId"), - }) - PayTransactionSuccessMessage convertTransaction(PayNotifyTaskDO payTransactionNotifyTaskDO); - - @Mappings({ - @Mapping(source = "refund.transactionId", target = "transactionId"), - @Mapping(source = "refund.orderId", target = "orderId"), - @Mapping(source = "refund.refundId", target = "refundId"), - }) - PayRefundSuccessMessage convertRefund(PayNotifyTaskDO payTransactionNotifyTaskDO); - -} diff --git a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/dao/PayNotifyLogMapper.java b/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/dao/PayNotifyLogMapper.java deleted file mode 100644 index 61fb4c8db..000000000 --- a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/dao/PayNotifyLogMapper.java +++ /dev/null @@ -1,11 +0,0 @@ -package cn.iocoder.mall.pay.biz.dao; - -import cn.iocoder.mall.pay.biz.dataobject.PayNotifyLogDO; -import org.springframework.stereotype.Repository; - -@Repository -public interface PayNotifyLogMapper { - - void insert(PayNotifyLogDO entity); - -} diff --git a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/dao/PayNotifyTaskMapper.java b/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/dao/PayNotifyTaskMapper.java deleted file mode 100644 index feb9a47ed..000000000 --- a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/dao/PayNotifyTaskMapper.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.iocoder.mall.pay.biz.dao; - -import cn.iocoder.mall.pay.biz.dataobject.PayNotifyTaskDO; -import org.springframework.stereotype.Repository; - -import java.util.List; - -@Repository -public interface PayNotifyTaskMapper { - - void insert(PayNotifyTaskDO entity); - - int update(PayNotifyTaskDO entity); - - /** - * 获得需要通知的 PayTransactionNotifyTaskDO 记录。需要满足如下条件: - * - * 1. status 非成功 - * 2. nextNotifyTime 小于当前时间 - * 3. lastExecuteTime > nextNotifyTime - * - * @return PayTransactionNotifyTaskDO 数组 - */ - List selectByNotify(); - -} diff --git a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionMapper.java b/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionMapper.java index e5fbccca1..cb341a4c8 100644 --- a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionMapper.java +++ b/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionMapper.java @@ -11,9 +11,6 @@ import java.util.List; @Repository public interface PayTransactionMapper { - int update(@Param("entity") PayTransactionDO entity, - @Param("whereStatus") Integer whereStatus); - int updateForRefundTotal(@Param("id") Integer id, @Param("refundTotalIncr") Integer refundTotalIncr); diff --git a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/service/PayNotifyServiceImpl.java b/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/service/PayNotifyServiceImpl.java deleted file mode 100644 index b2ecc1f8b..000000000 --- a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/service/PayNotifyServiceImpl.java +++ /dev/null @@ -1,75 +0,0 @@ -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.PayRefundSuccessMessage; -import cn.iocoder.mall.pay.api.message.PayTransactionSuccessMessage; -import cn.iocoder.mall.pay.biz.convert.PayNotifyConvert; -import cn.iocoder.mall.pay.biz.dao.PayNotifyTaskMapper; -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 PayNotifyTaskMapper payTransactionNotifyTaskMapper; - - @Resource - private RocketMQTemplate rocketMQTemplate; - - @Deprecated // 参见 PayRefundSuccessConsumer 类的说明 - 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 消息 - sendNotifyMessage(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 - sendNotifyMessage(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); - } - - public void sendNotifyMessage(PayNotifyTaskDO notifyTask) { - if (PayNotifyType.TRANSACTION.getValue().equals(notifyTask.getType())) { - rocketMQTemplate.convertAndSend(PayTransactionSuccessMessage.TOPIC, - PayNotifyConvert.INSTANCE.convertTransaction(notifyTask)); - } else if (PayNotifyType.REFUND.getValue().equals(notifyTask.getType())) { - rocketMQTemplate.convertAndSend(PayRefundSuccessMessage.TOPIC, - PayNotifyConvert.INSTANCE.convertRefund(notifyTask)); - } else { - throw new IllegalArgumentException(String.format("通知任务(%s) 无法发送通知消息", notifyTask.toString())); - } - } - -} diff --git a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/service/PayTransactionServiceImpl.java b/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/service/PayTransactionServiceImpl.java index c7bc51730..907f772d3 100644 --- a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/service/PayTransactionServiceImpl.java +++ b/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/service/PayTransactionServiceImpl.java @@ -50,63 +50,6 @@ public class PayTransactionServiceImpl implements PayTransactionService { return payTransactionExtensionMapper.selectById(id); } - @Override - @Transactional - public Boolean updateTransactionPaySuccess(Integer payChannel, String params) { - // TODO 芋艿,记录回调日志 - // 解析传入的参数,成 TransactionSuccessBO 对象 - AbstractPaySDK paySDK = PaySDKFactory.getSDK(payChannel); - CommonResult paySuccessResult = paySDK.parseTransactionSuccessParams(params); - if (paySuccessResult.isError()) { - throw ServiceExceptionUtil.exception(paySuccessResult.getCode(), paySuccessResult.getMessage()); - } - // TODO 芋艿,先最严格的校验。即使调用方重复调用,实际哪个订单已经被重复回调的支付,也返回 false 。也没问题,因为实际已经回调成功了。 - // 1.1 查询 PayTransactionExtensionDO - PayTransactionExtensionDO extension = payTransactionExtensionMapper.selectByTransactionCode(paySuccessResult.getData().getTransactionCode()); - if (extension == null) { - throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_EXTENSION_NOT_FOUND.getCode()); - } - if (!PayTransactionStatusEnum.WAITING.getValue().equals(extension.getStatus())) { // 校验状态,必须是待支付 - throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_EXTENSION_STATUS_IS_NOT_WAITING.getCode()); - } - // 1.2 更新 PayTransactionExtensionDO - PayTransactionExtensionDO updatePayTransactionExtension = new PayTransactionExtensionDO() - .setId(extension.getId()) - .setStatus(PayTransactionStatusEnum.SUCCESS.getValue()) - .setExtensionData(params); - 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({}) 更新为已支付]", extension.getId()); - // 2.1 判断 PayTransactionDO 是否处于待支付 - PayTransactionDO transaction = payTransactionMapper.selectById(extension.getTransactionId()); - if (transaction == null) { - throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_NOT_FOUND.getCode()); - } - 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(transaction.getId()) - .setStatus(PayTransactionStatusEnum.SUCCESS.getValue()) - .setExtensionId(extension.getId()) - .setPayChannel(payChannel) - .setPaymentTime(paySuccessResult.getData().getPaymentTime()) - .setNotifyTime(new Date()) - .setTradeNo(paySuccessResult.getData().getTradeNo()); - 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({}) 更新为已支付]", transaction.getId()); - // 3 新增 PayNotifyTaskDO 注释原因,参见 PayRefundSuccessConsumer 类。 -// payNotifyService.addTransactionNotifyTask(transaction, extension); - // 返回结果 - return true; - } - @Override public List getTransactionList(Collection ids) { return PayTransactionConvert.INSTANCE.convertList(payTransactionMapper.selectListByIds(ids)); diff --git a/moved/pay/pay-application/src/main/resources/mapper/PayNotifyLogMapper.xml b/moved/pay/pay-application/src/main/resources/mapper/PayNotifyLogMapper.xml deleted file mode 100644 index bb0600627..000000000 --- a/moved/pay/pay-application/src/main/resources/mapper/PayNotifyLogMapper.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - INSERT INTO notify_log ( - notify_id, request, response, status - ) VALUES ( - #{notifyId}, #{request}, #{response}, #{status} - ) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/moved/pay/pay-application/src/main/resources/mapper/PayNotifyTaskMapper.xml b/moved/pay/pay-application/src/main/resources/mapper/PayNotifyTaskMapper.xml deleted file mode 100644 index 74651ac19..000000000 --- a/moved/pay/pay-application/src/main/resources/mapper/PayNotifyTaskMapper.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - id, app_id, type, - status, next_notify_time, last_execute_time, notify_times, max_notify_times, - create_time - - - - - - - - - INSERT INTO notify_task ( - app_id, type, - status, next_notify_time, notify_times, max_notify_times, - `transaction`, refund - ) VALUES ( - #{appId}, #{type}, - #{status}, #{nextNotifyTime}, #{notifyTimes}, #{maxNotifyTimes}, - #{transaction, typeHandler=cn.iocoder.common.framework.mybatis.JSONTypeHandler}, - #{refund, typeHandler=cn.iocoder.common.framework.mybatis.JSONTypeHandler} - ) - - - - UPDATE notify_task - - - , status = #{status} - - - , next_notify_time = #{nextNotifyTime} - - - , last_execute_time = #{lastExecuteTime} - - - , notify_times = #{notifyTimes} - - - WHERE id = #{id} - - - - - diff --git a/moved/pay/pay-application/src/main/resources/mapper/PayTransactionExtensionMapper.xml b/moved/pay/pay-application/src/main/resources/mapper/PayTransactionExtensionMapper.xml index 489f98e12..7452c428a 100644 --- a/moved/pay/pay-application/src/main/resources/mapper/PayTransactionExtensionMapper.xml +++ b/moved/pay/pay-application/src/main/resources/mapper/PayTransactionExtensionMapper.xml @@ -7,32 +7,6 @@ create_ip, status, create_time - - INSERT INTO transaction_extension ( - transaction_id, pay_channel, transaction_code, extension_data, - create_ip, status - ) VALUES ( - #{transactionId}, #{payChannel}, #{transactionCode}, #{extensionData}, - #{createIp}, #{status} - ) - - - - UPDATE transaction_extension - - - , extension_data = #{entity.extensionData} - - - , status = #{entity.status} - - - WHERE id = #{entity.id} - - AND status = #{whereStatus} - - - +// SELECT +// +// FROM notify_task +// WHERE status IN (1, 4, 5) +// AND next_notify_time NOW() +// AND last_execute_time > next_notify_time +// + +} diff --git a/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/dal/mysql/mapper/transaction/PayTransactionMapper.java b/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/dal/mysql/mapper/transaction/PayTransactionMapper.java index 29b102da0..927599e62 100644 --- a/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/dal/mysql/mapper/transaction/PayTransactionMapper.java +++ b/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/dal/mysql/mapper/transaction/PayTransactionMapper.java @@ -13,6 +13,11 @@ public interface PayTransactionMapper extends BaseMapper { // new QueryWrapperX()); // } + default int update(PayTransactionDO entity, Integer whereStatus) { + return update(entity, new QueryWrapper() + .eq("id", entity.getId()).eq("status", whereStatus)); + } + default PayTransactionDO selectByAppIdAndOrderId(String appId, String orderId) { return selectOne(new QueryWrapper().eq("app_id", appId) .eq("order_id", orderId)); diff --git a/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/mq/producer/PayMQProducer.java b/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/mq/producer/PayMQProducer.java new file mode 100644 index 000000000..6e465f356 --- /dev/null +++ b/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/mq/producer/PayMQProducer.java @@ -0,0 +1,45 @@ +package cn.iocoder.mall.payservice.mq.producer; + +import cn.iocoder.mall.payservice.mq.producer.message.PayRefundSuccessMessage; +import cn.iocoder.mall.payservice.mq.producer.message.PayTransactionSuccessMessage; +import lombok.extern.slf4j.Slf4j; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.client.producer.SendStatus; +import org.apache.rocketmq.spring.core.RocketMQTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +// TODO 芋艿:后续优化下,考虑下一致性 +public class PayMQProducer { + + @Autowired + private RocketMQTemplate template; + + public void sendPayRefundNotifyTaskMessage(PayRefundSuccessMessage message, Integer refundId, Integer transactionId, String orderId) { + message.setRefundId(refundId).setTransactionId(transactionId).setOrderId(orderId); + try { + SendResult sendResult = template.syncSend(PayTransactionSuccessMessage.TOPIC, message); + if (!SendStatus.SEND_OK.equals(sendResult.getSendStatus())) { + log.error("[sendPayRefundNotifyTaskMessage][消息({}) 发送更新消息失败,结果为({})]", message, sendResult); + } + } catch (Throwable throwable) { + log.error("[sendPayRefundNotifyTaskMessage][消息({}) 发送更新消息失败,发生异常]", message, throwable); + } + } + + public void sendPayTransactionNotifyTaskMessage(PayTransactionSuccessMessage message, Integer transactionId, String orderId) { + message.setTransactionId(transactionId).setOrderId(orderId); + try { + SendResult sendResult = template.syncSend(PayTransactionSuccessMessage.TOPIC, message); + if (!SendStatus.SEND_OK.equals(sendResult.getSendStatus())) { + log.error("[sendPayTransactionNotifyTaskMessage][消息({}) 发送更新消息失败,结果为({})]", message, sendResult); + } + } catch (Throwable throwable) { + log.error("[sendPayTransactionNotifyTaskMessage][消息({}) 发送更新消息失败,发生异常]", message, throwable); + } + } + + +} diff --git a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api/message/AbstractPayNotifySuccessMessage.java b/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/mq/producer/message/AbstractPayNotifySuccessMessage.java similarity index 87% rename from moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api/message/AbstractPayNotifySuccessMessage.java rename to pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/mq/producer/message/AbstractPayNotifySuccessMessage.java index 28ffb6a0f..c821baf89 100644 --- a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api/message/AbstractPayNotifySuccessMessage.java +++ b/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/mq/producer/message/AbstractPayNotifySuccessMessage.java @@ -1,4 +1,4 @@ -package cn.iocoder.mall.pay.api.message; +package cn.iocoder.mall.payservice.mq.producer.message; import lombok.Data; import lombok.experimental.Accessors; diff --git a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api/message/PayRefundSuccessMessage.java b/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/mq/producer/message/PayRefundSuccessMessage.java similarity index 79% rename from moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api/message/PayRefundSuccessMessage.java rename to pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/mq/producer/message/PayRefundSuccessMessage.java index d1aaed2d3..6a878b0d3 100644 --- a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api/message/PayRefundSuccessMessage.java +++ b/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/mq/producer/message/PayRefundSuccessMessage.java @@ -1,6 +1,7 @@ -package cn.iocoder.mall.pay.api.message; +package cn.iocoder.mall.payservice.mq.producer.message; import lombok.Data; +import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; /** @@ -8,6 +9,7 @@ import lombok.experimental.Accessors; */ @Data @Accessors(chain = true) +@EqualsAndHashCode(callSuper = true) public class PayRefundSuccessMessage extends AbstractPayNotifySuccessMessage { public static final String TOPIC = "PAY_REFUND_SUCCESS"; diff --git a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api/message/PayTransactionSuccessMessage.java b/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/mq/producer/message/PayTransactionSuccessMessage.java similarity index 77% rename from moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api/message/PayTransactionSuccessMessage.java rename to pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/mq/producer/message/PayTransactionSuccessMessage.java index 7e396c882..98213493c 100644 --- a/moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/api/message/PayTransactionSuccessMessage.java +++ b/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/mq/producer/message/PayTransactionSuccessMessage.java @@ -1,6 +1,7 @@ -package cn.iocoder.mall.pay.api.message; +package cn.iocoder.mall.payservice.mq.producer.message; import lombok.Data; +import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; /** @@ -8,6 +9,7 @@ import lombok.experimental.Accessors; */ @Data @Accessors(chain = true) +@EqualsAndHashCode(callSuper = true) public class PayTransactionSuccessMessage extends AbstractPayNotifySuccessMessage { public static final String TOPIC = "PAY_TRANSACTION_SUCCESS"; diff --git a/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/rpc/transaction/PayTransactionRpcImpl.java b/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/rpc/transaction/PayTransactionRpcImpl.java index 0339b4e55..a023fa8f8 100644 --- a/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/rpc/transaction/PayTransactionRpcImpl.java +++ b/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/rpc/transaction/PayTransactionRpcImpl.java @@ -29,4 +29,10 @@ public class PayTransactionRpcImpl implements PayTransactionRpc { return success(payTransactionService.getPayTransaction(getReqDTO)); } + @Override + public CommonResult updatePayTransactionSuccess(PayTransactionSuccessReqDTO successReqDTO) { + return success(payTransactionService.updateTransactionPaySuccess(successReqDTO.getPayChannel(), + successReqDTO.getParams())); + } + } diff --git a/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/service/notify/PayNotifyService.java b/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/service/notify/PayNotifyService.java new file mode 100644 index 000000000..d74e6967a --- /dev/null +++ b/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/service/notify/PayNotifyService.java @@ -0,0 +1,18 @@ +package cn.iocoder.mall.payservice.service.notify; + +import cn.iocoder.mall.payservice.dal.mysql.dataobject.refund.PayRefundDO; +import cn.iocoder.mall.payservice.dal.mysql.dataobject.transaction.PayTransactionDO; +import cn.iocoder.mall.payservice.dal.mysql.dataobject.transaction.PayTransactionExtensionDO; + +/** + * 支付通知 Service 接口 + */ +public interface PayNotifyService { + + // TODO 芋艿:后续优化下,不要暴露 entity 出来 + void addPayRefundNotifyTask(PayRefundDO refund); + + // TODO 芋艿:后续优化下,不要暴露 entity 出来 + void addPayTransactionNotifyTask(PayTransactionDO transaction, PayTransactionExtensionDO extension); + +} diff --git a/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/service/notify/impl/PayNotifyServiceImpl.java b/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/service/notify/impl/PayNotifyServiceImpl.java new file mode 100644 index 000000000..c4f802ec5 --- /dev/null +++ b/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/service/notify/impl/PayNotifyServiceImpl.java @@ -0,0 +1,70 @@ +package cn.iocoder.mall.payservice.service.notify.impl; + +import cn.iocoder.common.framework.util.DateUtil; +import cn.iocoder.mall.payservice.convert.notify.PayNotifyConvert; +import cn.iocoder.mall.payservice.dal.mysql.dataobject.notify.PayNotifyTaskDO; +import cn.iocoder.mall.payservice.dal.mysql.dataobject.refund.PayRefundDO; +import cn.iocoder.mall.payservice.dal.mysql.dataobject.transaction.PayTransactionDO; +import cn.iocoder.mall.payservice.dal.mysql.dataobject.transaction.PayTransactionExtensionDO; +import cn.iocoder.mall.payservice.dal.mysql.mapper.notify.PayNotifyTaskMapper; +import cn.iocoder.mall.payservice.enums.notify.PayNotifyStatusEnum; +import cn.iocoder.mall.payservice.enums.notify.PayNotifyType; +import cn.iocoder.mall.payservice.mq.producer.PayMQProducer; +import cn.iocoder.mall.payservice.service.notify.PayNotifyService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Calendar; + +/** + * 支付通知 Service 实现类 + */ +@Service +public class PayNotifyServiceImpl implements PayNotifyService { + + @Autowired + private PayNotifyTaskMapper payNotifyTaskMapper; + + @Autowired + private PayMQProducer payMQProducer; + + @Override + public void addPayRefundNotifyTask(PayRefundDO refund) { + PayNotifyTaskDO payNotifyTaskDO = this.createBasePayNotifyTaskDO(refund.getAppId(), refund.getNotifyUrl()) + .setType(PayNotifyType.REFUND.getType()); + // 设置 Refund 属性 + payNotifyTaskDO.setRefund(new PayNotifyTaskDO.Refund().setRefundId(refund.getId()) + .setTransactionId(refund.getTransactionId()).setOrderId(refund.getOrderId())); + // 保存到数据库 + payNotifyTaskMapper.insert(payNotifyTaskDO); + + // 发送 MQ 消息 + payMQProducer.sendPayRefundNotifyTaskMessage(PayNotifyConvert.INSTANCE.convertRefund(payNotifyTaskDO), + refund.getId(), refund.getTransactionId(), refund.getOrderId()); + } + + @Override + public void addPayTransactionNotifyTask(PayTransactionDO transaction, PayTransactionExtensionDO extension) { + PayNotifyTaskDO payNotifyTaskDO = this.createBasePayNotifyTaskDO(transaction.getAppId(), transaction.getNotifyUrl()) + .setType(PayNotifyType.TRANSACTION.getType()); + // 设置 Transaction 属性 + payNotifyTaskDO.setTransaction(new PayNotifyTaskDO.Transaction().setOrderId(transaction.getOrderId()) + .setTransactionId(extension.getTransactionId()).setTransactionExtensionId(extension.getId())); + // 保存到数据库 + payNotifyTaskMapper.insert(payNotifyTaskDO); + + // 发送 MQ 消息 + payMQProducer.sendPayTransactionNotifyTaskMessage(PayNotifyConvert.INSTANCE.convertTransaction(payNotifyTaskDO), + transaction.getId(), transaction.getOrderId()); + } + + private PayNotifyTaskDO createBasePayNotifyTaskDO(String appId, String notifyUrl) { + return new PayNotifyTaskDO() + .setAppId(appId) + .setStatus(PayNotifyStatusEnum.WAITING.getStatus()) + .setNotifyTimes(0).setMaxNotifyTimes(PayNotifyTaskDO.NOTIFY_FREQUENCY.length + 1) + .setNextNotifyTime(DateUtil.addDate(Calendar.SECOND, PayNotifyTaskDO.NOTIFY_FREQUENCY[0])) + .setNotifyUrl(notifyUrl); + } + +} diff --git a/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/service/transaction/PayTransactionService.java b/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/service/transaction/PayTransactionService.java index 8df1b7dc9..5b79b8971 100644 --- a/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/service/transaction/PayTransactionService.java +++ b/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/service/transaction/PayTransactionService.java @@ -31,4 +31,16 @@ public interface PayTransactionService { */ PayTransactionRespDTO getPayTransaction(PayTransactionGetReqDTO getReqDTO); + /** + * 更新交易支付成功 + * + * 该接口用于不同支付平台,支付成功后,回调该接口 + * + * @param payChannel 支付渠道 + * @param params 回调参数。 + * 因为不同平台,能够提供的参数不同,所以使用 String 类型统一接收,然后在使用不同的 AbstractThirdPayClient 进行处理。 + * @return 是否支付成功 + */ + Boolean updateTransactionPaySuccess(Integer payChannel, String params); + } diff --git a/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/service/transaction/impl/PayTransactionServiceImpl.java b/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/service/transaction/impl/PayTransactionServiceImpl.java index 722c4cb0e..9005924da 100644 --- a/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/service/transaction/impl/PayTransactionServiceImpl.java +++ b/pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/service/transaction/impl/PayTransactionServiceImpl.java @@ -6,6 +6,7 @@ import cn.iocoder.common.framework.util.MathUtil; import cn.iocoder.common.framework.vo.CommonResult; import cn.iocoder.mall.payservice.client.thirdpay.AbstractThirdPayClient; import cn.iocoder.mall.payservice.client.thirdpay.ThirdPayClientFactory; +import cn.iocoder.mall.payservice.client.thirdpay.dto.ThirdPayTransactionSuccessRespDTO; import cn.iocoder.mall.payservice.convert.transaction.PayTransactionConvert; import cn.iocoder.mall.payservice.dal.mysql.dataobject.transaction.PayTransactionDO; import cn.iocoder.mall.payservice.dal.mysql.dataobject.transaction.PayTransactionExtensionDO; @@ -15,16 +16,17 @@ import cn.iocoder.mall.payservice.enums.transaction.PayTransactionStatusEnum; import cn.iocoder.mall.payservice.rpc.app.dto.PayAppRespDTO; import cn.iocoder.mall.payservice.rpc.transaction.dto.*; import cn.iocoder.mall.payservice.service.app.PayAppService; +import cn.iocoder.mall.payservice.service.notify.PayNotifyService; import cn.iocoder.mall.payservice.service.transaction.PayTransactionService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.Date; -import static cn.iocoder.mall.payservice.enums.PayErrorCodeConstants.PAY_TRANSACTION_NOT_FOUND; -import static cn.iocoder.mall.payservice.enums.PayErrorCodeConstants.PAY_TRANSACTION_STATUS_IS_NOT_WAITING; +import static cn.iocoder.mall.payservice.enums.PayErrorCodeConstants.*; /** * 支付交易单 Service 实现类 @@ -41,6 +43,8 @@ public class PayTransactionServiceImpl implements PayTransactionService { @Autowired private PayAppService payAppService; + @Autowired + private PayNotifyService payNotifyService; @Override public Integer createPayTransaction(PayTransactionCreateReqDTO createReqDTO) { @@ -58,7 +62,7 @@ public class PayTransactionServiceImpl implements PayTransactionService { // 创建支付交易单 payTransaction = PayTransactionConvert.INSTANCE.convert(createReqDTO) - .setStatus(PayTransactionStatusEnum.WAITING.getValue()) + .setStatus(PayTransactionStatusEnum.WAITING.getStatus()) .setNotifyUrl(payAppRespDTO.getPayNotifyUrl()); payTransactionMapper.insert(payTransaction); // 最终返回 @@ -77,14 +81,14 @@ public class PayTransactionServiceImpl implements PayTransactionService { if (payTransaction == null) { // 是否存在 throw ServiceExceptionUtil.exception(PAY_TRANSACTION_NOT_FOUND); } - if (!PayTransactionStatusEnum.WAITING.getValue().equals(payTransaction.getStatus())) { // 校验状态,必须是待支付 + if (!PayTransactionStatusEnum.WAITING.getStatus().equals(payTransaction.getStatus())) { // 校验状态,必须是待支付 throw ServiceExceptionUtil.exception(PAY_TRANSACTION_STATUS_IS_NOT_WAITING); } // 插入 PayTransactionExtensionDO PayTransactionExtensionDO payTransactionExtensionDO = PayTransactionConvert.INSTANCE.convert(submitReqDTO) .setTransactionId(payTransaction.getId()).setTransactionCode(generateTransactionCode()) - .setStatus(PayTransactionStatusEnum.WAITING.getValue()); + .setStatus(PayTransactionStatusEnum.WAITING.getStatus()); payTransactionExtensionMapper.insert(payTransactionExtensionDO); // 调用三方接口 @@ -103,6 +107,64 @@ public class PayTransactionServiceImpl implements PayTransactionService { getReqDTO.getAppId(), getReqDTO.getOrderId())); } + @Override + @Transactional + public Boolean updateTransactionPaySuccess(Integer payChannel, String params) { + // TODO 芋艿,记录回调日志 + // 解析传入的参数,成 ThirdPayTransactionSuccessRespDTO 对象 + AbstractThirdPayClient thirdPayClient = ThirdPayClientFactory.getThirdPayClient(payChannel); + CommonResult paySuccessResult = thirdPayClient.parseTransactionSuccessParams(params); + paySuccessResult.checkError(); + + // TODO 芋艿,先最严格的校验。即使调用方重复调用,实际哪个订单已经被重复回调的支付,也返回 false 。也没问题,因为实际已经回调成功了。 + // 1.1 查询 PayTransactionExtensionDO + PayTransactionExtensionDO extension = payTransactionExtensionMapper.selectByTransactionCode(paySuccessResult.getData().getTransactionCode()); + if (extension == null) { + throw ServiceExceptionUtil.exception(PAY_TRANSACTION_EXTENSION_NOT_FOUND); + } + if (!PayTransactionStatusEnum.WAITING.getStatus().equals(extension.getStatus())) { // 校验状态,必须是待支付 + throw ServiceExceptionUtil.exception(PAY_TRANSACTION_EXTENSION_STATUS_IS_NOT_WAITING); + } + // 1.2 更新 PayTransactionExtensionDO + PayTransactionExtensionDO updatePayTransactionExtension = new PayTransactionExtensionDO() + .setId(extension.getId()) + .setStatus(PayTransactionStatusEnum.SUCCESS.getStatus()) + .setExtensionData(params); + int updateCounts = payTransactionExtensionMapper.update(updatePayTransactionExtension, PayTransactionStatusEnum.WAITING.getStatus()); + if (updateCounts == 0) { // 校验状态,必须是待支付 + throw ServiceExceptionUtil.exception(PAY_TRANSACTION_EXTENSION_STATUS_IS_NOT_WAITING); + } + log.info("[updateTransactionPaySuccess][PayTransactionExtensionDO({}) 更新为已支付]", extension.getId()); + + // 2.1 判断 PayTransactionDO 是否处于待支付 + PayTransactionDO transaction = payTransactionMapper.selectById(extension.getTransactionId()); + if (transaction == null) { + throw ServiceExceptionUtil.exception(PAY_TRANSACTION_NOT_FOUND); + } + if (!PayTransactionStatusEnum.WAITING.getStatus().equals(transaction.getStatus())) { // 校验状态,必须是待支付 + throw ServiceExceptionUtil.exception(PAY_TRANSACTION_STATUS_IS_NOT_WAITING); + } + // 2.2 更新 PayTransactionDO + PayTransactionDO updatePayTransaction = new PayTransactionDO() + .setId(transaction.getId()) + .setStatus(PayTransactionStatusEnum.SUCCESS.getStatus()) + .setExtensionId(extension.getId()) + .setPayChannel(payChannel) + .setPaymentTime(paySuccessResult.getData().getPaymentTime()) + .setNotifyTime(new Date()) + .setTradeNo(paySuccessResult.getData().getTradeNo()); + updateCounts = payTransactionMapper.update(updatePayTransaction, PayTransactionStatusEnum.WAITING.getStatus()); + if (updateCounts == 0) { // 校验状态,必须是待支付 + throw ServiceExceptionUtil.exception(PAY_TRANSACTION_STATUS_IS_NOT_WAITING); + } + log.info("[updateTransactionPaySuccess][PayTransactionDO({}) 更新为已支付]", transaction.getId()); + + // 3 新增 PayNotifyTaskDO 注释原因,参见 PayRefundSuccessConsumer 类。 + payNotifyService.addPayTransactionNotifyTask(transaction, extension); + // 返回结果 + return true; + } + private String generateTransactionCode() { // wx // 2014 diff --git a/shop-web-app/src/main/java/cn/iocoder/mall/shopweb/client/pay/PayTransactionClient.java b/shop-web-app/src/main/java/cn/iocoder/mall/shopweb/client/pay/PayTransactionClient.java index 684beab1d..48c54a428 100644 --- a/shop-web-app/src/main/java/cn/iocoder/mall/shopweb/client/pay/PayTransactionClient.java +++ b/shop-web-app/src/main/java/cn/iocoder/mall/shopweb/client/pay/PayTransactionClient.java @@ -2,10 +2,7 @@ package cn.iocoder.mall.shopweb.client.pay; import cn.iocoder.common.framework.vo.CommonResult; import cn.iocoder.mall.payservice.rpc.transaction.PayTransactionRpc; -import cn.iocoder.mall.payservice.rpc.transaction.dto.PayTransactionGetReqDTO; -import cn.iocoder.mall.payservice.rpc.transaction.dto.PayTransactionRespDTO; -import cn.iocoder.mall.payservice.rpc.transaction.dto.PayTransactionSubmitReqDTO; -import cn.iocoder.mall.payservice.rpc.transaction.dto.PayTransactionSubmitRespDTO; +import cn.iocoder.mall.payservice.rpc.transaction.dto.*; import org.apache.dubbo.config.annotation.DubboReference; import org.springframework.stereotype.Service; @@ -35,4 +32,10 @@ public class PayTransactionClient { return submitPayTransactionResult.getData(); } + public void updatePayTransactionSuccess(Integer payChannel, String params) { + CommonResult updatePayTransactionSuccessResult = payTransactionRpc.updatePayTransactionSuccess( + new PayTransactionSuccessReqDTO().setPayChannel(payChannel).setParams(params)); + updatePayTransactionSuccessResult.checkError(); + } + } diff --git a/shop-web-app/src/main/java/cn/iocoder/mall/shopweb/controller/pay/PayTransactionController.java b/shop-web-app/src/main/java/cn/iocoder/mall/shopweb/controller/pay/PayTransactionController.java index 38b50beb8..ec80ca4a3 100644 --- a/shop-web-app/src/main/java/cn/iocoder/mall/shopweb/controller/pay/PayTransactionController.java +++ b/shop-web-app/src/main/java/cn/iocoder/mall/shopweb/controller/pay/PayTransactionController.java @@ -2,6 +2,7 @@ package cn.iocoder.mall.shopweb.controller.pay; import cn.iocoder.common.framework.util.HttpUtil; import cn.iocoder.common.framework.vo.CommonResult; +import cn.iocoder.mall.payservice.enums.PayChannelEnum; import cn.iocoder.mall.security.user.core.context.UserSecurityContextHolder; import cn.iocoder.mall.shopweb.controller.pay.vo.transaction.PayTransactionRespVO; import cn.iocoder.mall.shopweb.controller.pay.vo.transaction.PayTransactionSubmitReqVO; @@ -14,10 +15,13 @@ import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; +import java.io.BufferedReader; +import java.io.IOException; import static cn.iocoder.common.framework.vo.CommonResult.success; @@ -31,6 +35,7 @@ public class PayTransactionController { @Autowired private PayTransactionService payTransactionService; + // TODO 芋艿:这个 API 定义可能不太太合适,应该改成支付交易单号 @GetMapping("/get") @ApiOperation("获得支付交易") @ApiImplicitParams({ @@ -43,6 +48,7 @@ public class PayTransactionController { return success(payTransactionService.getPayTransaction(UserSecurityContextHolder.getUserId(), appId, orderId)); } + // TODO 芋艿:这个 API 定义可能不太太合适,应该改成支付交易单号 @PostMapping("/submit") @ApiOperation("提交支付交易") @RequiresAuthenticate @@ -51,24 +57,25 @@ public class PayTransactionController { return success(payTransactionService.submitPayTransaction(submitReqVO, HttpUtil.getIp(request))); } -// @PostMapping(value = "pingxx_pay_success", consumes = MediaType.APPLICATION_JSON_VALUE) -//// @GetMapping(value = "pingxx_pay_success") -// public String pingxxPaySuccess(HttpServletRequest request) throws IOException { -// logger.info("[pingxxPaySuccess][被回调]"); -// // 读取 webhook -// StringBuilder sb = new StringBuilder(); -// try (BufferedReader reader = request.getReader()) { -// String line; -// while ((line = reader.readLine()) != null) { -// sb.append(line); -// } -// } -// -//// JSONObject bodyObj = JSON.parseObject(sb.toString()); -//// bodyObj.put("webhookId", bodyObj.remove("id")); -//// String body = bodyObj.toString(); -// payTransactionService.updateTransactionPaySuccess(PayChannelEnum.PINGXX.getId(), sb.toString()); -// return "success"; -// } + @PostMapping(value = "pingxx_pay_success", consumes = MediaType.APPLICATION_JSON_VALUE) + @ApiOperation("Pingxx 支付成功回调") +// @GetMapping(value = "pingxx_pay_success") + public String updatePayTransactionSuccess(HttpServletRequest request) throws IOException { + log.info("[pingxxPaySuccess][被回调]"); + // 读取 webhook + StringBuilder sb = new StringBuilder(); + try (BufferedReader reader = request.getReader()) { + String line; + while ((line = reader.readLine()) != null) { + sb.append(line); + } + } + +// JSONObject bodyObj = JSON.parseObject(sb.toString()); +// bodyObj.put("webhookId", bodyObj.remove("id")); +// String body = bodyObj.toString(); + payTransactionService.updatePayTransactionSuccess(PayChannelEnum.PINGXX.getId(), sb.toString()); + return "success"; + } } diff --git a/shop-web-app/src/main/java/cn/iocoder/mall/shopweb/service/pay/PayTransactionService.java b/shop-web-app/src/main/java/cn/iocoder/mall/shopweb/service/pay/PayTransactionService.java index 000ac72c7..92fca0757 100644 --- a/shop-web-app/src/main/java/cn/iocoder/mall/shopweb/service/pay/PayTransactionService.java +++ b/shop-web-app/src/main/java/cn/iocoder/mall/shopweb/service/pay/PayTransactionService.java @@ -17,7 +17,7 @@ public class PayTransactionService { public PayTransactionSubmitRespVO submitPayTransaction(PayTransactionSubmitReqVO submitReqVO, String ip) { PayTransactionSubmitRespDTO submitPayTransaction = payTransactionClient.submitPayTransaction( - PayTransactionConvert.INSTANCE.convert(submitReqVO)); + PayTransactionConvert.INSTANCE.convert(submitReqVO).setCreateIp(ip)); return PayTransactionConvert.INSTANCE.convert(submitPayTransaction); } @@ -25,4 +25,8 @@ public class PayTransactionService { return PayTransactionConvert.INSTANCE.convert(payTransactionClient.getPayTransaction(userId, appId, orderId)); } + public void updatePayTransactionSuccess(Integer payChannel, String params) { + payTransactionClient.updatePayTransactionSuccess(payChannel, params); + } + }