From 7d423c8ed214e163e030ba0894611af818b1a542 Mon Sep 17 00:00:00 2001
From: YunaiV <>
Date: Wed, 13 Mar 2019 20:27:53 +0800
Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E4=BB=98=E6=A8=A1=E5=9D=97=EF=BC=8C?=
=?UTF-8?q?=E8=B0=83=E9=80=9A=E5=AF=B9=20ping++=20=E7=9A=84=E8=B0=83?=
=?UTF-8?q?=E7=94=A8=EF=BC=8C=E4=BB=A5=E5=AE=9E=E7=8E=B0=E6=A8=A1=E6=8B=9F?=
=?UTF-8?q?=E6=94=AF=E4=BB=98=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
当然,整体代码还是有点乱,后面花点时间重构下~
现在,缺一个异步 MQ 通知业务方订单支付成功
---
common/common-framework/pom.xml | 6 ++
.../common/framework/util/DateUtil.java | 20 ++++
.../common/framework/util/MathUtil.java | 33 +++++++
.../controller/users/PayDemoController.java | 53 +++++++++-
.../users/PayTransactionController.java | 41 +++++++-
.../test/java/DubboGenericInvokerTest.java | 32 ++++++
.../iocoder/mall/pay/api/PayDemoService.java | 7 ++
.../mall/pay/api/PayTransactionService.java | 12 +++
.../pay/api/constant/PayErrorCodeEnum.java | 2 +
pay/pay-service-impl/pom.xml | 1 -
.../mall/pay/client/AbstractPaySDK.java | 3 +
.../iocoder/mall/pay/client/PingxxPaySDK.java | 15 ++-
.../pay/client/TransactionPaySuccessBO.java | 52 ++++++++++
.../config/ServiceExceptionConfiguration.java | 4 +-
.../dao/PayTransactionExtensionMapper.java | 8 +-
.../mall/pay/dao/PayTransactionMapper.java | 5 +
.../dao/PayTransactionNotifyTaskMapper.java | 13 +++
.../PayTransactionNotifyTaskDO.java | 15 ++-
.../mall/pay/service/PayDemoServiceImpl.java | 15 +++
.../mall/pay/service/PayServiceImpl.java | 97 ++++++++++++++++++-
.../main/resources/mapper/PayAppMapper.xml | 4 +-
.../mapper/PayTransactionExtensionMapper.xml | 44 +++++++++
.../resources/mapper/PayTransactionMapper.xml | 69 +++++++++++++
.../mapper/PayTransactionNotifyTaskMapper.xml | 44 +++++++++
24 files changed, 579 insertions(+), 16 deletions(-)
create mode 100644 common/common-framework/src/main/java/cn/iocoder/common/framework/util/DateUtil.java
create mode 100644 common/common-framework/src/main/java/cn/iocoder/common/framework/util/MathUtil.java
create mode 100644 pay/pay-application/src/test/java/DubboGenericInvokerTest.java
create mode 100644 pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/PayDemoService.java
create mode 100644 pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/client/TransactionPaySuccessBO.java
create mode 100644 pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/dao/PayTransactionNotifyTaskMapper.java
create mode 100644 pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/service/PayDemoServiceImpl.java
create mode 100644 pay/pay-service-impl/src/main/resources/mapper/PayTransactionExtensionMapper.xml
create mode 100644 pay/pay-service-impl/src/main/resources/mapper/PayTransactionMapper.xml
create mode 100644 pay/pay-service-impl/src/main/resources/mapper/PayTransactionNotifyTaskMapper.xml
diff --git a/common/common-framework/pom.xml b/common/common-framework/pom.xml
index d8f9e472f..52d055f6b 100644
--- a/common/common-framework/pom.xml
+++ b/common/common-framework/pom.xml
@@ -55,6 +55,12 @@
+
+ com.alibaba
+ fastjson
+ 1.2.56
+
+
diff --git a/common/common-framework/src/main/java/cn/iocoder/common/framework/util/DateUtil.java b/common/common-framework/src/main/java/cn/iocoder/common/framework/util/DateUtil.java
new file mode 100644
index 000000000..d5736e45e
--- /dev/null
+++ b/common/common-framework/src/main/java/cn/iocoder/common/framework/util/DateUtil.java
@@ -0,0 +1,20 @@
+package cn.iocoder.common.framework.util;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class DateUtil {
+
+ /**
+ * @param date 时间。若为空,则返回空串
+ * @param pattern 时间格式化
+ * @return 格式化后的时间字符串.
+ */
+ public static String format(Date date, String pattern) {
+ if (date == null) {
+ return "";
+ }
+ return new SimpleDateFormat(pattern).format(date);
+ }
+
+}
\ No newline at end of file
diff --git a/common/common-framework/src/main/java/cn/iocoder/common/framework/util/MathUtil.java b/common/common-framework/src/main/java/cn/iocoder/common/framework/util/MathUtil.java
new file mode 100644
index 000000000..4aafa732e
--- /dev/null
+++ b/common/common-framework/src/main/java/cn/iocoder/common/framework/util/MathUtil.java
@@ -0,0 +1,33 @@
+package cn.iocoder.common.framework.util;
+
+import java.util.Random;
+
+public class MathUtil {
+
+ /**
+ * 随机对象
+ */
+ private static final Random RANDOM = new Random(); // TODO 后续优化
+
+ /**
+ * 随机[min, max]范围内的数字
+ *
+ * @param min 随机开始
+ * @param max 随机结束
+ * @return 数字
+ */
+ public static int random(int min, int max) {
+ if (min == max) {
+ return min;
+ }
+ if (min > max) {
+ int temp = min;
+ min = max;
+ max = temp;
+ }
+ // 随即开始
+ int diff = max - min + 1;
+ return RANDOM.nextInt(diff) + min;
+ }
+
+}
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
index 5af8b5736..71ae866d6 100644
--- 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
@@ -31,7 +31,7 @@ public class PayDemoController {
// 调用【支付服务】,创建交易订单
PayTransactionCreateDTO payTransactionCreateDTO = new PayTransactionCreateDTO()
- .setAppId("1024")
+ .setAppId("POd4RC6a")
.setCreateIp(HttpUtil.getIp(request))
.setOrderId("1")
.setOrderSubject("商品名" )
@@ -43,4 +43,55 @@ public class PayDemoController {
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/PayTransactionController.java b/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/PayTransactionController.java
index e1285f418..bd3b25e44 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
@@ -1,12 +1,22 @@
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.PayTransactionSubmitBO;
+import cn.iocoder.mall.pay.api.constant.PayChannelEnum;
+import cn.iocoder.mall.pay.api.dto.PayTransactionSubmitDTO;
import com.alibaba.dubbo.config.annotation.Reference;
+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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
+import javax.servlet.http.HttpServletRequest;
+import java.io.BufferedReader;
+import java.io.IOException;
+
@RestController
@RequestMapping("users/transaction") // TODO 芋艿,理论来说,是用户无关的。这里先酱紫先~
public class PayTransactionController {
@@ -15,8 +25,35 @@ public class PayTransactionController {
private PayTransactionService payService;
@PostMapping("/submit") // TODO api 注释
- public CommonResult submit() { // TODO 1. params 2. result
- return null;
+ // TODO result 后面改下
+ public CommonResult submit(HttpServletRequest request,
+ @RequestParam("appId") String appId,
+ @RequestParam("orderId") String orderId,
+ @RequestParam("payChannel") Integer payChannel) {
+ PayTransactionSubmitDTO payTransactionSubmitDTO = new PayTransactionSubmitDTO()
+ .setAppId(appId).setOrderId(orderId).setPayChannel(payChannel)
+ .setCreateIp(HttpUtil.getIp(request));
+ // 提交支付提交
+ return payService.submitTransaction(payTransactionSubmitDTO);
+ }
+
+ @PostMapping(value = "pingxx_pay_success", consumes = MediaType.APPLICATION_JSON_VALUE)
+// @GetMapping(value = "pingxx_pay_success")
+ public String pingxxSuccess(HttpServletRequest request) throws IOException {
+ // 读取 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();
+ payService.updateTransactionPaySuccess(PayChannelEnum.PINGXX.getId(), sb.toString());
+ return "";
}
}
\ No newline at end of file
diff --git a/pay/pay-application/src/test/java/DubboGenericInvokerTest.java b/pay/pay-application/src/test/java/DubboGenericInvokerTest.java
new file mode 100644
index 000000000..b46a5f4d0
--- /dev/null
+++ b/pay/pay-application/src/test/java/DubboGenericInvokerTest.java
@@ -0,0 +1,32 @@
+import com.alibaba.dubbo.config.ApplicationConfig;
+import com.alibaba.dubbo.config.ReferenceConfig;
+import com.alibaba.dubbo.config.RegistryConfig;
+import com.alibaba.dubbo.rpc.service.GenericService;
+
+public class DubboGenericInvokerTest {
+
+ public static void main(String[] args) {
+ ApplicationConfig application = new ApplicationConfig();
+ application.setName("api-generic-consumer");
+
+ RegistryConfig registry = new RegistryConfig();
+ registry.setAddress("zookeeper://127.0.0.1:2181");
+
+ application.setRegistry(registry);
+
+ ReferenceConfig reference = new ReferenceConfig<>();
+ // 弱类型接口名
+ reference.setInterface("cn.iocoder.mall.pay.api.PayDemoService");
+ // 声明为泛化接口
+ reference.setGeneric(true);
+
+ reference.setApplication(application);
+
+ // 用com.alibaba.dubbo.rpc.service.GenericService可以替代所有接口引用
+ GenericService genericService = reference.get();
+
+ String name = (String) genericService.$invoke("updatePaySuccess", new String[]{String.class.getName()}, new Object[]{"1"});
+ System.out.println(name);
+ }
+
+}
\ No newline at end of file
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
new file mode 100644
index 000000000..77a500cad
--- /dev/null
+++ b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/PayDemoService.java
@@ -0,0 +1,7 @@
+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/PayTransactionService.java b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/PayTransactionService.java
index 51700b443..0e68a4dfa 100644
--- a/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/PayTransactionService.java
+++ b/pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/PayTransactionService.java
@@ -12,6 +12,18 @@ public interface PayTransactionService {
CommonResult submitTransaction(PayTransactionSubmitDTO payTransactionSubmitDTO);
+ /**
+ * 更新交易支付成功
+ *
+ * 该接口用于不同支付平台,支付成功后,回调该接口
+ *
+ * @param payChannel 支付渠道
+ * @param params 回调参数。
+ * 因为不同平台,能够提供的参数不同,所以使用 String 类型统一接收,然后在使用不同的 AbstractPaySDK 进行处理。
+ * @return 是否支付成功
+ */
+ CommonResult updateTransactionPaySuccess(Integer payChannel, String params);
+
CommonResult cancelTransaction(); // TODO 1. params 2. result
}
\ No newline at end of file
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 1d60cd387..c012a0cf6 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
@@ -15,6 +15,8 @@ public enum PayErrorCodeEnum {
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, "支付交易拓展单不处于待支付"),
;
private final int code;
diff --git a/pay/pay-service-impl/pom.xml b/pay/pay-service-impl/pom.xml
index 9513972f2..0cc2d3487 100644
--- a/pay/pay-service-impl/pom.xml
+++ b/pay/pay-service-impl/pom.xml
@@ -19,7 +19,6 @@
com.alibaba
dubbo
- compile
cn.iocoder.mall
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/client/AbstractPaySDK.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/client/AbstractPaySDK.java
index 8be86179b..ea2d25e35 100644
--- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/client/AbstractPaySDK.java
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/client/AbstractPaySDK.java
@@ -13,4 +13,7 @@ public abstract class AbstractPaySDK {
PayTransactionExtensionDO transactionExtension,
Map extra);
+ // TODO 芋艿,理论来说不会出现解析失败的情况,先返回这个参数列。等后面封装支付宝和微信支付的时候,在看看。
+ public abstract CommonResult parseTransactionPaySuccessParams(String params);
+
}
\ No newline at end of file
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/client/PingxxPaySDK.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/client/PingxxPaySDK.java
index 9c2e887b9..74d838a2e 100644
--- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/client/PingxxPaySDK.java
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/client/PingxxPaySDK.java
@@ -3,11 +3,14 @@ package cn.iocoder.mall.pay.client;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.pay.dataobject.PayTransactionDO;
import cn.iocoder.mall.pay.dataobject.PayTransactionExtensionDO;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.ImmutableMap;
import com.pingplusplus.Pingpp;
import com.pingplusplus.exception.*;
import com.pingplusplus.model.Charge;
+import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@@ -25,7 +28,7 @@ public class PingxxPaySDK extends AbstractPaySDK {
// 请求ping++
try {
Charge charge = Charge.create(reqObj);
-// System.out.println(charge.toString());
+ System.out.println(charge.toString());
return CommonResult.success(charge.toString());
} catch (AuthenticationException e) {
e.printStackTrace();
@@ -43,6 +46,16 @@ public class PingxxPaySDK extends AbstractPaySDK {
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) {
// 计算支付渠道和支付额外参数
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/client/TransactionPaySuccessBO.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/client/TransactionPaySuccessBO.java
new file mode 100644
index 000000000..97b420b57
--- /dev/null
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/client/TransactionPaySuccessBO.java
@@ -0,0 +1,52 @@
+package cn.iocoder.mall.pay.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/config/ServiceExceptionConfiguration.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/config/ServiceExceptionConfiguration.java
index 28f5be277..f057ffbc7 100644
--- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/config/ServiceExceptionConfiguration.java
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/config/ServiceExceptionConfiguration.java
@@ -1,7 +1,7 @@
package cn.iocoder.mall.pay.config;
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
-import cn.iocoder.mall.admin.api.constant.AdminErrorCodeEnum;
+import cn.iocoder.mall.pay.api.constant.PayErrorCodeEnum;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
@@ -18,7 +18,7 @@ public class ServiceExceptionConfiguration {
// } catch (IOException e) {
// throw new RuntimeException(e);
// }
- for (AdminErrorCodeEnum item : AdminErrorCodeEnum.values()) {
+ for (PayErrorCodeEnum item : PayErrorCodeEnum.values()) {
ServiceExceptionUtil.put(item.getCode(), item.getMessage());
}
}
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/dao/PayTransactionExtensionMapper.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/dao/PayTransactionExtensionMapper.java
index 118204e3f..128e8c042 100644
--- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/dao/PayTransactionExtensionMapper.java
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/dao/PayTransactionExtensionMapper.java
@@ -1,11 +1,17 @@
package cn.iocoder.mall.pay.dao;
import cn.iocoder.mall.pay.dataobject.PayTransactionExtensionDO;
+import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
@Repository
public interface PayTransactionExtensionMapper {
- void insert(PayTransactionExtensionDO payTransactionExtensionDO);
+ void insert(PayTransactionExtensionDO entity);
+
+ int update(@Param("entity") PayTransactionExtensionDO entity,
+ @Param("whereStatus") Integer whereStatus);
+
+ PayTransactionExtensionDO selectByTransactionCode(@Param("transactionCode") String transactionCode);
}
\ No newline at end of file
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/dao/PayTransactionMapper.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/dao/PayTransactionMapper.java
index 0e59255ac..028daec61 100644
--- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/dao/PayTransactionMapper.java
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/dao/PayTransactionMapper.java
@@ -9,7 +9,12 @@ public interface PayTransactionMapper {
void insert(PayTransactionDO entity);
+ int update(@Param("entity") PayTransactionDO entity,
+ @Param("whereStatus") Integer whereStatus);
+
PayTransactionDO selectByAppIdAndOrderId(@Param("appId") String appId,
@Param("orderId") String orderId);
+ PayTransactionDO selectById(@Param("id") Integer appId);
+
}
\ No newline at end of file
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/dao/PayTransactionNotifyTaskMapper.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/dao/PayTransactionNotifyTaskMapper.java
new file mode 100644
index 000000000..cb6097010
--- /dev/null
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/dao/PayTransactionNotifyTaskMapper.java
@@ -0,0 +1,13 @@
+package cn.iocoder.mall.pay.dao;
+
+import cn.iocoder.mall.pay.dataobject.PayTransactionNotifyTaskDO;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface PayTransactionNotifyTaskMapper {
+
+ void insert(PayTransactionNotifyTaskDO entity);
+
+ int update(PayTransactionNotifyTaskDO entity);
+
+}
\ No newline at end of file
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/dataobject/PayTransactionNotifyTaskDO.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/dataobject/PayTransactionNotifyTaskDO.java
index d4c4364eb..5ed6d2253 100644
--- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/dataobject/PayTransactionNotifyTaskDO.java
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/dataobject/PayTransactionNotifyTaskDO.java
@@ -51,9 +51,10 @@ public class PayTransactionNotifyTaskDO extends BaseDO {
* 最大可通知次数
*/
private Integer maxNotifyTimes;
-
- // TODO notify url
-
+ /**
+ * 通知地址
+ */
+ private String notifyUrl;
public Integer getTransactionId() {
return transactionId;
@@ -136,4 +137,12 @@ public class PayTransactionNotifyTaskDO extends BaseDO {
return this;
}
+ public String getNotifyUrl() {
+ return notifyUrl;
+ }
+
+ public PayTransactionNotifyTaskDO setNotifyUrl(String notifyUrl) {
+ this.notifyUrl = notifyUrl;
+ return this;
+ }
}
\ No newline at end of file
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/service/PayDemoServiceImpl.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/service/PayDemoServiceImpl.java
new file mode 100644
index 000000000..b60fd451c
--- /dev/null
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/service/PayDemoServiceImpl.java
@@ -0,0 +1,15 @@
+package cn.iocoder.mall.pay.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 "你好呀";
+ }
+
+}
\ No newline at end of file
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/service/PayServiceImpl.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/service/PayServiceImpl.java
index b265c97b1..5893010a9 100644
--- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/service/PayServiceImpl.java
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/service/PayServiceImpl.java
@@ -1,25 +1,33 @@
package cn.iocoder.mall.pay.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.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.client.AbstractPaySDK;
import cn.iocoder.mall.pay.client.PaySDKFactory;
+import cn.iocoder.mall.pay.client.TransactionPaySuccessBO;
import cn.iocoder.mall.pay.convert.PayTransactionConvert;
import cn.iocoder.mall.pay.dao.PayTransactionExtensionMapper;
import cn.iocoder.mall.pay.dao.PayTransactionMapper;
+import cn.iocoder.mall.pay.dao.PayTransactionNotifyTaskMapper;
import cn.iocoder.mall.pay.dataobject.PayAppDO;
import cn.iocoder.mall.pay.dataobject.PayTransactionDO;
import cn.iocoder.mall.pay.dataobject.PayTransactionExtensionDO;
+import cn.iocoder.mall.pay.dataobject.PayTransactionNotifyTaskDO;
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 java.util.Date;
@@ -34,6 +42,8 @@ public class PayServiceImpl implements PayTransactionService {
@Autowired
private PayTransactionExtensionMapper payTransactionExtensionMapper;
@Autowired
+ private PayTransactionNotifyTaskMapper payTransactionNotifyTaskMapper;
+ @Autowired
private PayAppServiceImpl payAppService;
@Override
@@ -77,17 +87,18 @@ 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.WAITTING.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("TODO")
+ .setTransactionCode(generateTransactionCode())
.setStatus(PayTransactionStatusEnum.WAITTING.getValue());
payTransactionExtensionMapper.insert(payTransactionExtensionDO);
// 调用三方接口
- CommonResult invokeResult = PaySDKFactory.getSDK(payTransactionSubmitDTO.getPayChannel()).submitTransaction(payTransaction, payTransactionExtensionDO, null); // TODO 暂时传入 extra = null
+ AbstractPaySDK paySDK = PaySDKFactory.getSDK(payTransactionSubmitDTO.getPayChannel());
+ CommonResult invokeResult = paySDK.submitTransaction(payTransaction, payTransactionExtensionDO, null); // TODO 暂时传入 extra = null
if (invokeResult.isError()) {
return CommonResult.error(invokeResult);
}
@@ -99,8 +110,88 @@ public class PayServiceImpl implements PayTransactionService {
}
@Override
+ @Transactional
+ public CommonResult updateTransactionPaySuccess(Integer payChannel, String params) {
+ // TODO 芋艿,记录回调日志
+ // 解析传入的参数,成 TransactionPaySuccessBO 对象
+ AbstractPaySDK paySDK = PaySDKFactory.getSDK(payChannel);
+ CommonResult paySuccessResult = paySDK.parseTransactionPaySuccessParams(params);
+ if (paySuccessResult.isError()) {
+ return CommonResult.error(paySuccessResult);
+ }
+ // TODO 芋艿,先最严格的校验。即使调用方重复调用,实际哪个订单已经被重复回调的支付,也返回 false 。也没问题,因为实际已经回调成功了。
+ // 1.1 查询 PayTransactionExtensionDO
+ PayTransactionExtensionDO payTransactionExtension = payTransactionExtensionMapper.selectByTransactionCode(paySuccessResult.getData().getTransactionCode());
+ if (payTransactionExtension == null) {
+ return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_EXTENSION_NOT_FOUND.getCode());
+ }
+ if (!PayTransactionStatusEnum.WAITTING.getValue().equals(payTransactionExtension.getStatus())) { // 校验状态,必须是待支付
+ return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_EXTENSION_STATUS_IS_NOT_WAITING.getCode());
+ }
+ // 1.2 更新 PayTransactionExtensionDO
+ PayTransactionExtensionDO updatePayTransactionExtension = new PayTransactionExtensionDO()
+ .setId(payTransactionExtension.getId())
+ .setStatus(PayTransactionStatusEnum.SUCCESS.getValue())
+ .setExtensionData(params);
+ int updateCounts = payTransactionExtensionMapper.update(updatePayTransactionExtension, PayTransactionStatusEnum.WAITTING.getValue());
+ if (updateCounts == 0) { // 校验状态,必须是待支付
+ throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_EXTENSION_STATUS_IS_NOT_WAITING.getCode());
+ }
+ // 2.1
+ PayTransactionDO payTransactionDO = payTransactionMapper.selectById(payTransactionExtension.getTransactionId());
+ if (payTransactionDO == null) {
+ return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_NOT_FOUND.getCode());
+ }
+ if (!PayTransactionStatusEnum.WAITTING.getValue().equals(payTransactionDO.getStatus())) { // 校验状态,必须是待支付
+ throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_STATUS_IS_NOT_WAITING.getCode());
+ }
+ // 2.2 更新 PayTransactionDO
+ PayTransactionDO updatePayTransaction = new PayTransactionDO()
+ .setId(payTransactionDO.getId())
+ .setStatus(PayTransactionStatusEnum.SUCCESS.getValue())
+ .setExtensionId(payTransactionExtension.getId())
+ .setPayChannel(payChannel)
+ .setPaymentTime(paySuccessResult.getData().getPaymentTime())
+ .setNotifyTime(new Date())
+ .setTradeNo(paySuccessResult.getData().getTradeNo());
+ updateCounts = payTransactionMapper.update(updatePayTransaction, PayTransactionStatusEnum.WAITTING.getValue());
+ if (updateCounts == 0) { // 校验状态,必须是待支付 TODO 这种类型,需要思考下。需要返回错误,但是又要保证事务回滚
+ throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_STATUS_IS_NOT_WAITING.getCode());
+ }
+ // 3. 插入
+ PayTransactionNotifyTaskDO payTransactionNotifyTask = new PayTransactionNotifyTaskDO()
+ .setTransactionId(payTransactionExtension.getTransactionId()).setTransactionExtensionId(payTransactionExtension.getId())
+ .setAppId(payTransactionDO.getAppId()).setOrderId(payTransactionDO.getOrderId())
+ .setStatus(PayTransactionNotifyStatusEnum.WAITING.getValue())
+ .setNotifyTimes(0).setMaxNotifyTimes(5)
+ .setNotifyUrl(payTransactionDO.getNotifyUrl());
+ payTransactionNotifyTaskMapper.insert(payTransactionNotifyTask);
+ // 返回结果
+ return CommonResult.success(true);
+ }
+
+ @Override // TODO 芋艿,后面去实现
public CommonResult cancelTransaction() {
return null;
}
+ 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) // 随机。为什么是这个范围,因为偷懒
+ ;
+ }
+
+
}
\ No newline at end of file
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 b581aae1f..8d219ee9f 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, status, create_time
+ id, name, notify_url, status, create_time
@@ -27,7 +27,7 @@
-