From d8643194eea02f4a1407248c1b6cc771297c6d6b Mon Sep 17 00:00:00 2001 From: zhangsan <646228430@qq.com> Date: Wed, 16 Jul 2025 14:01:48 +0800 Subject: [PATCH] =?UTF-8?q?7.16=20=E5=B0=8F=E5=95=86=E5=9C=BA=E5=AF=B9?= =?UTF-8?q?=E6=8E=A5=E6=8B=BC=E5=9B=A2=E7=BB=93=E7=AE=97=E9=83=A8=E5=88=86?= =?UTF-8?q?=EF=BC=8C=E6=94=AF=E4=BB=98=E6=88=90=E5=8A=9F=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E7=BB=84=E9=98=9F=E4=BF=A1=E6=81=AF=EF=BC=8C=E7=BB=84=E9=98=9F?= =?UTF-8?q?=E6=88=90=E5=8A=9F=E8=A7=A6=E5=8F=91=E5=9B=9E=E8=B0=83=3D?= =?UTF-8?q?=E3=80=8B=E6=A8=A1=E6=8B=9F=E5=8F=91=E8=B4=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/dev-ops/mysql/sql/0713paymall.sql | 50 --------------- docs/dev-ops/mysql/sql/0716paymall.sql | 52 +++++++++++++++ docs/dev-ops/nginx/html/form.html | 4 +- .../main/java/edu/whut/api/IPayService.java | 8 +++ .../edu/whut/api/dto/NotifyRequestDTO.java | 18 ++++++ .../src/main/resources/application-dev.yml | 4 +- .../mybatis/mapper/pay_order_mapper.xml | 19 ++++++ .../src/test/java/edu/whut/test/ApiTest.java | 23 ++++++- .../whut/test/domain/OrderServiceTest.java | 4 +- .../adapter/repository/IGoodsRepository.java | 10 +++ .../domain/goods/service/GoodsService.java | 22 +++++++ .../domain/goods/service/IGoodsService.java | 10 +++ .../order/adapter/port/IProductPort.java | 3 + .../adapter/repository/IOrderRepository.java | 9 ++- .../order/model/entity/OrderEntity.java | 2 + .../order/model/valobj/OrderStatusVO.java | 3 +- .../domain/order/service/IOrderService.java | 5 +- .../domain/order/service/OrderService.java | 23 ++++++- .../adapter/port/ProductPort.java | 33 ++++++++++ .../adapter/repository/GoodsRepository.java | 22 +++++++ .../adapter/repository/OrderRepository.java | 64 +++++++++++++++++-- .../whut/infrastructure/dao/IOrderDao.java | 6 ++ .../gateway/IGroupBuyMarketService.java | 12 ++++ .../whut/trigger/http/AliPayController.java | 29 ++++++++- .../whut/trigger/job/NoPayNotifyOrderJob.java | 9 +-- .../trigger/job/TimeoutCloseOrderJob.java | 4 +- .../listener/OrderPaySuccessListener.java | 17 ++++- 27 files changed, 385 insertions(+), 80 deletions(-) delete mode 100644 docs/dev-ops/mysql/sql/0713paymall.sql create mode 100644 docs/dev-ops/mysql/sql/0716paymall.sql create mode 100644 pay-mall-api/src/main/java/edu/whut/api/dto/NotifyRequestDTO.java create mode 100644 pay-mall-domain/src/main/java/edu/whut/domain/goods/adapter/repository/IGoodsRepository.java create mode 100644 pay-mall-domain/src/main/java/edu/whut/domain/goods/service/GoodsService.java create mode 100644 pay-mall-domain/src/main/java/edu/whut/domain/goods/service/IGoodsService.java create mode 100644 pay-mall-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/GoodsRepository.java diff --git a/docs/dev-ops/mysql/sql/0713paymall.sql b/docs/dev-ops/mysql/sql/0713paymall.sql deleted file mode 100644 index a7b24d6..0000000 --- a/docs/dev-ops/mysql/sql/0713paymall.sql +++ /dev/null @@ -1,50 +0,0 @@ -/* - Navicat Premium Data Transfer - - Source Server : group_buy_local - Source Server Type : MySQL - Source Server Version : 80042 - Source Host : localhost:13306 - Source Schema : pay-mall - - Target Server Type : MySQL - Target Server Version : 80042 - File Encoding : 65001 - - Date: 15/07/2025 14:36:57 -*/ - -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - --- ---------------------------- --- Table structure for pay_order --- ---------------------------- -DROP TABLE IF EXISTS `pay_order`; -CREATE TABLE `pay_order` ( - `id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID', - `user_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户ID', - `product_id` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品ID', - `product_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品名称', - `order_id` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '订单ID', - `order_time` datetime NOT NULL COMMENT '下单时间', - `total_amount` decimal(8, 2) UNSIGNED NULL DEFAULT NULL COMMENT '订单金额', - `status` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '订单状态;create-创建完成、pay_wait-等待支付、pay_success-支付成功、deal_done-交易完成、close-订单关单', - `pay_url` varchar(2014) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '支付信息', - `pay_time` datetime NULL DEFAULT NULL COMMENT '支付时间', - `market_type` tinyint(1) NULL DEFAULT NULL COMMENT '营销类型;0无营销、1拼团营销', - `market_deduction_amount` decimal(8, 2) NULL DEFAULT NULL COMMENT '营销金额;优惠金额', - `pay_amount` decimal(8, 2) NOT NULL COMMENT '支付金额', - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - PRIMARY KEY (`id`) USING BTREE, - UNIQUE INDEX `uq_order_id`(`order_id` ASC) USING BTREE, - INDEX `idx_user_id_product_id`(`user_id` ASC, `product_id` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; - --- ---------------------------- --- Records of pay_order --- ---------------------------- -INSERT INTO `pay_order` VALUES (18, 'smile02', '9890001', 'MyBatisBook', '855240590150', '2025-07-15 06:35:57', 100.00, 'PAY_WAIT', '
\n\n\n
\n', NULL, 1, 20.00, 80.00, '2025-07-15 14:35:56', '2025-07-15 14:35:57'); - -SET FOREIGN_KEY_CHECKS = 1; diff --git a/docs/dev-ops/mysql/sql/0716paymall.sql b/docs/dev-ops/mysql/sql/0716paymall.sql new file mode 100644 index 0000000..4edc432 --- /dev/null +++ b/docs/dev-ops/mysql/sql/0716paymall.sql @@ -0,0 +1,52 @@ +/* + Navicat Premium Data Transfer + + Source Server : group_buy_local + Source Server Type : MySQL + Source Server Version : 80042 + Source Host : localhost:13306 + Source Schema : pay-mall + + Target Server Type : MySQL + Target Server Version : 80042 + File Encoding : 65001 + + Date: 16/07/2025 13:59:35 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for pay_order +-- ---------------------------- +DROP TABLE IF EXISTS `pay_order`; +CREATE TABLE `pay_order` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `user_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户ID', + `product_id` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品ID', + `product_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品名称', + `order_id` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '订单ID', + `order_time` datetime NOT NULL COMMENT '下单时间', + `total_amount` decimal(8, 2) UNSIGNED NULL DEFAULT NULL COMMENT '订单金额', + `status` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '订单状态;create-创建完成、pay_wait-等待支付、pay_success-支付成功、deal_done-交易完成、close-订单关单', + `pay_url` varchar(2014) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '支付信息', + `pay_time` datetime NULL DEFAULT NULL COMMENT '支付时间', + `market_type` tinyint(1) NULL DEFAULT NULL COMMENT '营销类型;0无营销、1拼团营销', + `market_deduction_amount` decimal(8, 2) NULL DEFAULT NULL COMMENT '营销金额;优惠金额', + `pay_amount` decimal(8, 2) NOT NULL COMMENT '支付金额', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `uq_order_id`(`order_id` ASC) USING BTREE, + INDEX `idx_user_id_product_id`(`user_id` ASC, `product_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of pay_order +-- ---------------------------- +INSERT INTO `pay_order` VALUES (31, 'smile01', '9890001', 'MyBatisBook', '376456387082', '2025-07-16 13:47:35', 100.00, 'DEAL_DONE', '
\n\n\n
\n', '2025-07-16 13:50:29', 1, 20.00, 80.00, '2025-07-16 13:47:35', '2025-07-16 13:58:39'); +INSERT INTO `pay_order` VALUES (32, 'smile02', '9890001', 'MyBatisBook', '503529040337', '2025-07-16 13:55:51', 100.00, 'DEAL_DONE', '
\n\n\n
\n', '2025-07-16 13:56:47', 1, 20.00, 80.00, '2025-07-16 13:55:50', '2025-07-16 13:58:39'); +INSERT INTO `pay_order` VALUES (33, 'smile03', '9890001', 'MyBatisBook', '274640446882', '2025-07-16 13:57:47', 100.00, 'DEAL_DONE', '
\n\n\n
\n', '2025-07-16 13:58:39', 1, 20.00, 80.00, '2025-07-16 13:57:47', '2025-07-16 13:58:40'); + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/docs/dev-ops/nginx/html/form.html b/docs/dev-ops/nginx/html/form.html index 1b82032..71fe6ea 100644 --- a/docs/dev-ops/nginx/html/form.html +++ b/docs/dev-ops/nginx/html/form.html @@ -1,5 +1,5 @@ -
- + +
\ No newline at end of file diff --git a/pay-mall-api/src/main/java/edu/whut/api/IPayService.java b/pay-mall-api/src/main/java/edu/whut/api/IPayService.java index a7d285e..64cd2ea 100644 --- a/pay-mall-api/src/main/java/edu/whut/api/IPayService.java +++ b/pay-mall-api/src/main/java/edu/whut/api/IPayService.java @@ -1,10 +1,18 @@ package edu.whut.api; import edu.whut.api.dto.CreatePayRequestDTO; +import edu.whut.api.dto.NotifyRequestDTO; import edu.whut.api.response.Response; public interface IPayService { Response createPayOrder(CreatePayRequestDTO createPayRequestDTO); + /** + * 拼团结算回调 + * + * @param requestDTO 请求对象 + * @return 返参,success 成功 + */ + String groupBuyNotify(NotifyRequestDTO requestDTO); } diff --git a/pay-mall-api/src/main/java/edu/whut/api/dto/NotifyRequestDTO.java b/pay-mall-api/src/main/java/edu/whut/api/dto/NotifyRequestDTO.java new file mode 100644 index 0000000..a4ee159 --- /dev/null +++ b/pay-mall-api/src/main/java/edu/whut/api/dto/NotifyRequestDTO.java @@ -0,0 +1,18 @@ +package edu.whut.api.dto; + +import lombok.Data; + +import java.util.List; + +/** + * 回调请求对象 + */ +@Data +public class NotifyRequestDTO { + + /** 组队ID */ + private String teamId; + /** 外部单号 */ + private List outTradeNoList; + +} diff --git a/pay-mall-app/src/main/resources/application-dev.yml b/pay-mall-app/src/main/resources/application-dev.yml index 7675090..593e3d6 100644 --- a/pay-mall-app/src/main/resources/application-dev.yml +++ b/pay-mall-app/src/main/resources/application-dev.yml @@ -11,7 +11,7 @@ app: # SC 渠道配置 - 拼团对接渠道值、回调通知 group-buy-market: api-url: http://127.0.0.1:8091 - notify-url: http://127.0.0.1:8091/api/v1/test/group_buy_notify + notify-url: http://127.0.0.1:8092/api/v1/alipay/group_buy_notify source: s01 chanel: c01 @@ -31,7 +31,7 @@ spring: datasource: username: root password: 123456 - url: jdbc:mysql://127.0.0.1:13306/pay-mall?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC&useSSL=true + url: jdbc:mysql://127.0.0.1:13306/pay-mall?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai&useSSL=true driver-class-name: com.mysql.cj.jdbc.Driver hikari: pool-name: Retail_HikariCP diff --git a/pay-mall-app/src/main/resources/mybatis/mapper/pay_order_mapper.xml b/pay-mall-app/src/main/resources/mybatis/mapper/pay_order_mapper.xml index 9042ba3..0e9a421 100644 --- a/pay-mall-app/src/main/resources/mybatis/mapper/pay_order_mapper.xml +++ b/pay-mall-app/src/main/resources/mybatis/mapper/pay_order_mapper.xml @@ -66,4 +66,23 @@ LIMIT 10 + + update pay_order set status = 'MARKET', update_time = now() + where order_id in + + #{orderId} + + + + + + + update pay_order set status = 'DEAL_DONE', update_time = now() + where order_id = #{orderId} + + diff --git a/pay-mall-app/src/test/java/edu/whut/test/ApiTest.java b/pay-mall-app/src/test/java/edu/whut/test/ApiTest.java index 025c536..d665826 100644 --- a/pay-mall-app/src/test/java/edu/whut/test/ApiTest.java +++ b/pay-mall-app/src/test/java/edu/whut/test/ApiTest.java @@ -1,19 +1,40 @@ package edu.whut.test; +import com.alibaba.fastjson.JSON; +import com.google.common.eventbus.EventBus; +import edu.whut.domain.order.adapter.event.PaySuccessMessageEvent; +import edu.whut.types.event.BaseEvent; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; +import javax.annotation.Resource; +import java.util.concurrent.CountDownLatch; + @Slf4j @RunWith(SpringRunner.class) @SpringBootTest public class ApiTest { + @Resource + private EventBus eventBus; + + @Resource + private PaySuccessMessageEvent paySuccessMessageEvent; + @Test - public void test() { + public void test() throws InterruptedException { + + BaseEvent.EventMessage paySuccessMessageEventMessage = paySuccessMessageEvent.buildEventMessage( + PaySuccessMessageEvent.PaySuccessMessage.builder() + .tradeNo("1100000111") + .build()); + + eventBus.post(JSON.toJSONString(paySuccessMessageEventMessage.getData())); log.info("测试完成"); + new CountDownLatch(1).await(); } } diff --git a/pay-mall-app/src/test/java/edu/whut/test/domain/OrderServiceTest.java b/pay-mall-app/src/test/java/edu/whut/test/domain/OrderServiceTest.java index 063d2ce..87f9471 100644 --- a/pay-mall-app/src/test/java/edu/whut/test/domain/OrderServiceTest.java +++ b/pay-mall-app/src/test/java/edu/whut/test/domain/OrderServiceTest.java @@ -24,9 +24,9 @@ public class OrderServiceTest { @Test public void test_createOrder() throws Exception { ShopCartEntity shopCartEntity = new ShopCartEntity(); - shopCartEntity.setUserId("smile02"); + shopCartEntity.setUserId("smile03"); shopCartEntity.setProductId("9890001"); - shopCartEntity.setTeamId(null); + shopCartEntity.setTeamId("71752028"); shopCartEntity.setActivityId(100123L); shopCartEntity.setMarketTypeVO(MarketTypeVO.GROUP_BUY_MARKET); diff --git a/pay-mall-domain/src/main/java/edu/whut/domain/goods/adapter/repository/IGoodsRepository.java b/pay-mall-domain/src/main/java/edu/whut/domain/goods/adapter/repository/IGoodsRepository.java new file mode 100644 index 0000000..bc7f932 --- /dev/null +++ b/pay-mall-domain/src/main/java/edu/whut/domain/goods/adapter/repository/IGoodsRepository.java @@ -0,0 +1,10 @@ +package edu.whut.domain.goods.adapter.repository; + +/** + * 结算仓储 + */ +public interface IGoodsRepository { + + void changeOrderDealDone(String orderId); + +} diff --git a/pay-mall-domain/src/main/java/edu/whut/domain/goods/service/GoodsService.java b/pay-mall-domain/src/main/java/edu/whut/domain/goods/service/GoodsService.java new file mode 100644 index 0000000..6c28c22 --- /dev/null +++ b/pay-mall-domain/src/main/java/edu/whut/domain/goods/service/GoodsService.java @@ -0,0 +1,22 @@ +package edu.whut.domain.goods.service; +import edu.whut.domain.goods.adapter.repository.IGoodsRepository; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +/** + * 结算服务 + */ +@Service +public class GoodsService implements IGoodsService { + + @Resource + private IGoodsRepository repository; + + + @Override + public void changeOrderDealDone(String orderId) { + repository.changeOrderDealDone(orderId); + } + +} diff --git a/pay-mall-domain/src/main/java/edu/whut/domain/goods/service/IGoodsService.java b/pay-mall-domain/src/main/java/edu/whut/domain/goods/service/IGoodsService.java new file mode 100644 index 0000000..28d97fe --- /dev/null +++ b/pay-mall-domain/src/main/java/edu/whut/domain/goods/service/IGoodsService.java @@ -0,0 +1,10 @@ +package edu.whut.domain.goods.service; + +/** + * 结算服务 + */ +public interface IGoodsService { + + void changeOrderDealDone(String tradeNo); + +} diff --git a/pay-mall-domain/src/main/java/edu/whut/domain/order/adapter/port/IProductPort.java b/pay-mall-domain/src/main/java/edu/whut/domain/order/adapter/port/IProductPort.java index 3fd0e55..c546186 100644 --- a/pay-mall-domain/src/main/java/edu/whut/domain/order/adapter/port/IProductPort.java +++ b/pay-mall-domain/src/main/java/edu/whut/domain/order/adapter/port/IProductPort.java @@ -4,10 +4,13 @@ package edu.whut.domain.order.adapter.port; import edu.whut.domain.order.model.entity.MarketPayDiscountEntity; import edu.whut.domain.order.model.entity.ProductEntity; +import java.util.Date; + public interface IProductPort { ProductEntity queryProductByProductId(String productId); MarketPayDiscountEntity lockMarketPayOrder(String userId, String teamId, Long activityId, String productId, String orderId); + void settlementMarketPayOrder(String userId, String orderId, Date orderTime); } diff --git a/pay-mall-domain/src/main/java/edu/whut/domain/order/adapter/repository/IOrderRepository.java b/pay-mall-domain/src/main/java/edu/whut/domain/order/adapter/repository/IOrderRepository.java index de7f372..0f346c5 100644 --- a/pay-mall-domain/src/main/java/edu/whut/domain/order/adapter/repository/IOrderRepository.java +++ b/pay-mall-domain/src/main/java/edu/whut/domain/order/adapter/repository/IOrderRepository.java @@ -5,6 +5,7 @@ import edu.whut.domain.order.model.entity.OrderEntity; import edu.whut.domain.order.model.entity.PayOrderEntity; import edu.whut.domain.order.model.entity.ShopCartEntity; +import java.util.Date; import java.util.List; public interface IOrderRepository { @@ -14,11 +15,17 @@ public interface IOrderRepository { void updateOrderPayInfo(PayOrderEntity payOrderEntity); - void changeOrderPaySuccess(String orderId); + void changeOrderPaySuccess(String orderId, Date payTime); + + void changeMarketOrderPaySuccess(String orderId); List queryNoPayNotifyOrder(); List queryTimeoutCloseOrderList(); boolean changeOrderClose(String orderId); + + void changeOrderMarketSettlement(List outTradeNoList); + + OrderEntity queryOrderByOrderId(String orderId); } diff --git a/pay-mall-domain/src/main/java/edu/whut/domain/order/model/entity/OrderEntity.java b/pay-mall-domain/src/main/java/edu/whut/domain/order/model/entity/OrderEntity.java index 4ecdfcb..3d5a69e 100644 --- a/pay-mall-domain/src/main/java/edu/whut/domain/order/model/entity/OrderEntity.java +++ b/pay-mall-domain/src/main/java/edu/whut/domain/order/model/entity/OrderEntity.java @@ -14,6 +14,8 @@ import java.util.Date; @NoArgsConstructor public class OrderEntity { + // 用户ID + private String userId; private String productId; private String productName; private String orderId; diff --git a/pay-mall-domain/src/main/java/edu/whut/domain/order/model/valobj/OrderStatusVO.java b/pay-mall-domain/src/main/java/edu/whut/domain/order/model/valobj/OrderStatusVO.java index b5cb8e3..a9a402d 100644 --- a/pay-mall-domain/src/main/java/edu/whut/domain/order/model/valobj/OrderStatusVO.java +++ b/pay-mall-domain/src/main/java/edu/whut/domain/order/model/valobj/OrderStatusVO.java @@ -12,7 +12,8 @@ public enum OrderStatusVO { PAY_SUCCESS("PAY_SUCCESS", "支付成功 - 接收到支付回调消息"), DEAL_DONE("DEAL_DONE", "交易完成 - 商品发货完成"), CLOSE("CLOSE", "超时关单 - 超市未支付"), - ; + MARKET("MARKET", "营销结算 - 拼团组队完成"), + ; private final String code; private final String desc; diff --git a/pay-mall-domain/src/main/java/edu/whut/domain/order/service/IOrderService.java b/pay-mall-domain/src/main/java/edu/whut/domain/order/service/IOrderService.java index 190e36a..c7a37e0 100644 --- a/pay-mall-domain/src/main/java/edu/whut/domain/order/service/IOrderService.java +++ b/pay-mall-domain/src/main/java/edu/whut/domain/order/service/IOrderService.java @@ -4,13 +4,14 @@ package edu.whut.domain.order.service; import edu.whut.domain.order.model.entity.PayOrderEntity; import edu.whut.domain.order.model.entity.ShopCartEntity; +import java.util.Date; import java.util.List; public interface IOrderService { PayOrderEntity createOrder(ShopCartEntity shopCartEntity) throws Exception; - void changeOrderPaySuccess(String orderId); + void changeOrderPaySuccess(String orderId, Date orderTime); List queryNoPayNotifyOrder(); @@ -18,4 +19,6 @@ public interface IOrderService { boolean changeOrderClose(String orderId); + void changeOrderMarketSettlement(List outTradeNoList); + } diff --git a/pay-mall-domain/src/main/java/edu/whut/domain/order/service/OrderService.java b/pay-mall-domain/src/main/java/edu/whut/domain/order/service/OrderService.java index 6335b3b..0bf78a1 100644 --- a/pay-mall-domain/src/main/java/edu/whut/domain/order/service/OrderService.java +++ b/pay-mall-domain/src/main/java/edu/whut/domain/order/service/OrderService.java @@ -7,6 +7,7 @@ import edu.whut.domain.order.adapter.port.IProductPort; import edu.whut.domain.order.adapter.repository.IOrderRepository; import edu.whut.domain.order.model.aggregate.CreateOrderAggregate; import edu.whut.domain.order.model.entity.MarketPayDiscountEntity; +import edu.whut.domain.order.model.entity.OrderEntity; import edu.whut.domain.order.model.entity.PayOrderEntity; import edu.whut.domain.order.model.valobj.MarketTypeVO; import edu.whut.domain.order.model.valobj.OrderStatusVO; @@ -16,6 +17,7 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.math.BigDecimal; +import java.util.Date; import java.util.List; @Slf4j @@ -89,8 +91,20 @@ public class OrderService extends AbstractOrderService{ * 标记订单为支付成功,并发布支付成功事件 */ @Override - public void changeOrderPaySuccess(String orderId) { - repository.changeOrderPaySuccess(orderId); + public void changeOrderPaySuccess(String orderId, Date payTime) { + OrderEntity orderEntity = repository.queryOrderByOrderId(orderId); + if (null == orderEntity) return; + + //走拼团的流程 + if (MarketTypeVO.GROUP_BUY_MARKET.getCode().equals(orderEntity.getMarketType())) { + repository.changeMarketOrderPaySuccess(orderId); + // 发起拼团系统的营销结算。这个过程可以是http/rpc直接调用,也可以发一个商城交易支付完成的mq消息,之后拼团系统自己接收做结算。 + port.settlementMarketPayOrder(orderEntity.getUserId(), orderId, payTime); + } else { + //不走拼团的流程 + repository.changeOrderPaySuccess(orderId, payTime); + } + } /** @@ -116,4 +130,9 @@ public class OrderService extends AbstractOrderService{ public boolean changeOrderClose(String orderId) { return repository.changeOrderClose(orderId); } + + @Override + public void changeOrderMarketSettlement(List outTradeNoList) { + repository.changeOrderMarketSettlement(outTradeNoList); + } } diff --git a/pay-mall-infrastructure/src/main/java/edu/whut/infrastructure/adapter/port/ProductPort.java b/pay-mall-infrastructure/src/main/java/edu/whut/infrastructure/adapter/port/ProductPort.java index 960e23a..3cf8270 100644 --- a/pay-mall-infrastructure/src/main/java/edu/whut/infrastructure/adapter/port/ProductPort.java +++ b/pay-mall-infrastructure/src/main/java/edu/whut/infrastructure/adapter/port/ProductPort.java @@ -3,6 +3,8 @@ package edu.whut.infrastructure.adapter.port; import com.alibaba.fastjson.JSON; import edu.whut.api.dto.LockMarketPayOrderRequestDTO; import edu.whut.api.dto.LockMarketPayOrderResponseDTO; +import edu.whut.api.dto.SettlementMarketPayOrderRequestDTO; +import edu.whut.api.dto.SettlementMarketPayOrderResponseDTO; import edu.whut.api.response.Response; import edu.whut.domain.order.adapter.port.IProductPort; import edu.whut.domain.order.model.entity.MarketPayDiscountEntity; @@ -17,6 +19,8 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import retrofit2.Call; +import java.util.Date; + @Component @RequiredArgsConstructor @Slf4j @@ -94,4 +98,33 @@ public class ProductPort implements IProductPort { } } + @Override + public void settlementMarketPayOrder(String userId, String orderId, Date orderTime) { + SettlementMarketPayOrderRequestDTO requestDTO = new SettlementMarketPayOrderRequestDTO(); + requestDTO.setSource(source); + requestDTO.setChannel(chanel); + requestDTO.setUserId(userId); + requestDTO.setOutTradeNo(orderId); + requestDTO.setOutTradeTime(orderTime); + + try { + Call> call = groupBuyMarketService.settlementMarketPayOrder(requestDTO); + + // 获取结果 + Response response = call.execute().body(); + log.info("营销结算{} requestDTO:{} responseDTO:{}", userId, JSON.toJSONString(requestDTO), JSON.toJSONString(response)); + if (null == response) return; + + // 异常判断 + if (!"0000".equals(response.getCode())) { + log.info("营销结算返回,code={}, info={}", response.getCode(), response.getInfo()); + throw new AppException(response.getCode(), response.getInfo()); + } + + } catch (Exception e) { + log.error("营销结算失败 {}", userId, e); + } + } + + } diff --git a/pay-mall-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/GoodsRepository.java b/pay-mall-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/GoodsRepository.java new file mode 100644 index 0000000..d85f36a --- /dev/null +++ b/pay-mall-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/GoodsRepository.java @@ -0,0 +1,22 @@ +package edu.whut.infrastructure.adapter.repository; +import edu.whut.domain.goods.adapter.repository.IGoodsRepository; +import edu.whut.infrastructure.dao.IOrderDao; +import org.springframework.stereotype.Repository; + +import javax.annotation.Resource; + +/** + * 结算仓储服务 + */ +@Repository +public class GoodsRepository implements IGoodsRepository { + + @Resource + private IOrderDao orderDao; + + @Override + public void changeOrderDealDone(String orderId) { + orderDao.changeOrderDealDone(orderId); + } + +} diff --git a/pay-mall-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/OrderRepository.java b/pay-mall-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/OrderRepository.java index 5db7252..3976020 100644 --- a/pay-mall-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/OrderRepository.java +++ b/pay-mall-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/OrderRepository.java @@ -1,5 +1,6 @@ package edu.whut.infrastructure.adapter.repository; +import com.alibaba.fastjson.JSON; import com.google.common.eventbus.EventBus; import edu.whut.domain.order.adapter.event.PaySuccessMessageEvent; import edu.whut.domain.order.adapter.repository.IOrderRepository; @@ -16,8 +17,8 @@ import edu.whut.types.event.BaseEvent; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; -import javax.annotation.Resource; import java.math.BigDecimal; +import java.util.Date; import java.util.List; @Repository @@ -108,20 +109,33 @@ public class OrderRepository implements IOrderRepository { * 标记订单为支付成功,并发布支付成功事件 */ @Override - public void changeOrderPaySuccess(String orderId) { + public void changeOrderPaySuccess(String orderId, Date payTime) { // 更新状态为 PAY_SUCCESS 并记录支付时间 PayOrder payOrderReq = new PayOrder(); payOrderReq.setOrderId(orderId); payOrderReq.setStatus(OrderStatusVO.PAY_SUCCESS.getCode()); + payOrderReq.setPayTime(payTime); orderDao.changeOrderPaySuccess(payOrderReq); - // 构建并发布支付成功消息给 EventBus + // 构建事件消息 BaseEvent.EventMessage evtMsg = paySuccessMessageEvent.buildEventMessage( PaySuccessMessageEvent.PaySuccessMessage.builder() - .tradeNo(orderId) + .tradeNo(orderId) // 将订单号作为消息内容 .build() ); - eventBus.post(evtMsg.getData()); + PaySuccessMessageEvent.PaySuccessMessage paySuccessMessage = evtMsg.getData(); + eventBus.post(JSON.toJSONString(paySuccessMessage)); //发布到 EventBus + } + + /** + * 标记拼团订单为支付成功(仅更新状态,不发布事件) + */ + @Override + public void changeMarketOrderPaySuccess(String orderId) { + PayOrder payOrderReq = new PayOrder(); + payOrderReq.setOrderId(orderId); + payOrderReq.setStatus(OrderStatusVO.PAY_SUCCESS.getCode()); + orderDao.changeOrderPaySuccess(payOrderReq); } /** @@ -148,4 +162,44 @@ public class OrderRepository implements IOrderRepository { public boolean changeOrderClose(String orderId) { return orderDao.changeOrderClose(orderId); } + + + @Override + public void changeOrderMarketSettlement(List outTradeNoList) { + // 更新拼团结算状态 + orderDao.changeOrderMarketSettlement(outTradeNoList); + + // 循环成功发送消息 - 一般在公司的场景里,还会有job任务扫描超时没有结算的订单,查询订单状态。查询对方服务端的接口,会被限制一次查询多少,频次多少。 + outTradeNoList.forEach(outTradeNo -> { + BaseEvent.EventMessage paySuccessMessageEventMessage = paySuccessMessageEvent.buildEventMessage( + PaySuccessMessageEvent.PaySuccessMessage.builder() + .tradeNo(outTradeNo) + .build()); + PaySuccessMessageEvent.PaySuccessMessage paySuccessMessage = paySuccessMessageEventMessage.getData(); + + eventBus.post(JSON.toJSONString(paySuccessMessage)); + }); + } + + /** + * 根据订单id查询订单 + */ + @Override + public OrderEntity queryOrderByOrderId(String orderId) { + PayOrder payOrder = orderDao.queryOrderByOrderId(orderId); + if (null == orderId) return null; + + return OrderEntity.builder() + .userId(payOrder.getUserId()) + .productId(payOrder.getProductId()) + .productName(payOrder.getProductName()) + .orderId(payOrder.getOrderId()) + .orderTime(payOrder.getOrderTime()) + .totalAmount(payOrder.getTotalAmount()) + .payUrl(payOrder.getPayUrl()) + .marketType(payOrder.getMarketType()) + .marketDeductionAmount(payOrder.getMarketDeductionAmount()) + .payAmount(payOrder.getPayAmount()) + .build(); + } } diff --git a/pay-mall-infrastructure/src/main/java/edu/whut/infrastructure/dao/IOrderDao.java b/pay-mall-infrastructure/src/main/java/edu/whut/infrastructure/dao/IOrderDao.java index 9ebc523..cd689fb 100644 --- a/pay-mall-infrastructure/src/main/java/edu/whut/infrastructure/dao/IOrderDao.java +++ b/pay-mall-infrastructure/src/main/java/edu/whut/infrastructure/dao/IOrderDao.java @@ -1,6 +1,7 @@ package edu.whut.infrastructure.dao; import edu.whut.infrastructure.dao.po.PayOrder; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; import java.util.List; @@ -21,5 +22,10 @@ public interface IOrderDao { boolean changeOrderClose(String orderId); + void changeOrderMarketSettlement(@Param("outTradeNoList") List outTradeNoList); + + PayOrder queryOrderByOrderId(String orderId); + + void changeOrderDealDone(String orderId); } diff --git a/pay-mall-infrastructure/src/main/java/edu/whut/infrastructure/gateway/IGroupBuyMarketService.java b/pay-mall-infrastructure/src/main/java/edu/whut/infrastructure/gateway/IGroupBuyMarketService.java index 24f4388..27928c9 100644 --- a/pay-mall-infrastructure/src/main/java/edu/whut/infrastructure/gateway/IGroupBuyMarketService.java +++ b/pay-mall-infrastructure/src/main/java/edu/whut/infrastructure/gateway/IGroupBuyMarketService.java @@ -2,6 +2,8 @@ package edu.whut.infrastructure.gateway; import edu.whut.api.dto.LockMarketPayOrderRequestDTO; import edu.whut.api.dto.LockMarketPayOrderResponseDTO; +import edu.whut.api.dto.SettlementMarketPayOrderRequestDTO; +import edu.whut.api.dto.SettlementMarketPayOrderResponseDTO; import edu.whut.api.response.Response; import retrofit2.Call; import retrofit2.http.Body; @@ -21,4 +23,14 @@ public interface IGroupBuyMarketService { @POST("api/v1/gbm/trade/lock_market_pay_order") Call> lockMarketPayOrder(@Body LockMarketPayOrderRequestDTO requestDTO); + /** + * 营销结算 + * + * @param requestDTO 结算商品信息 + * @return 结算结果信息 + */ + @POST("api/v1/gbm/trade/settlement_market_pay_order") + Call> settlementMarketPayOrder(@Body SettlementMarketPayOrderRequestDTO requestDTO); + + } diff --git a/pay-mall-trigger/src/main/java/edu/whut/trigger/http/AliPayController.java b/pay-mall-trigger/src/main/java/edu/whut/trigger/http/AliPayController.java index 347cdd1..594178b 100644 --- a/pay-mall-trigger/src/main/java/edu/whut/trigger/http/AliPayController.java +++ b/pay-mall-trigger/src/main/java/edu/whut/trigger/http/AliPayController.java @@ -1,8 +1,10 @@ package edu.whut.trigger.http; +import com.alibaba.fastjson.JSON; import com.alipay.api.AlipayApiException; import com.alipay.api.internal.util.AlipaySignature; import edu.whut.api.IPayService; import edu.whut.api.dto.CreatePayRequestDTO; +import edu.whut.api.dto.NotifyRequestDTO; import edu.whut.api.response.Response; import edu.whut.domain.order.model.entity.PayOrderEntity; import edu.whut.domain.order.model.entity.ShopCartEntity; @@ -14,6 +16,8 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.HashMap; import java.util.Map; @@ -67,8 +71,28 @@ public class AliPayController implements IPayService { } } + /** + * 拼团完成(目标人数已达成)后的回调地址,由group_buy_market调用 + */ + @PostMapping("/group_buy_notify") + @Override + public String groupBuyNotify(@RequestBody NotifyRequestDTO requestDTO) { + log.info("拼团回调,组队完成,结算开始 {}", JSON.toJSONString(requestDTO)); + try { + // 营销结算 + orderService.changeOrderMarketSettlement(requestDTO.getOutTradeNoList()); + return "success"; + } catch (Exception e) { + log.info("拼团回调,组队完成,结算失败 {}", JSON.toJSONString(requestDTO)); + return "error"; + } + } + + /** + * 用户支付成功后的回调地址 + */ @PostMapping("/alipay_notify_url") - public String payNotify(HttpServletRequest request) throws AlipayApiException { + public String payNotify(HttpServletRequest request) throws AlipayApiException, ParseException { log.info("支付回调,消息接收 {}", request.getParameter("trade_status")); if (!request.getParameter("trade_status").equals("TRADE_SUCCESS")) { @@ -104,7 +128,8 @@ public class AliPayController implements IPayService { log.info("支付回调,买家付款金额: {}", params.get("buyer_pay_amount")); log.info("支付回调,支付回调,更新订单 {}", tradeNo); - orderService.changeOrderPaySuccess(tradeNo); + // 后续处理,更新订单状态...进入下一阶段:如发货 + orderService.changeOrderPaySuccess(tradeNo, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(params.get("gmt_payment"))); return "success"; } diff --git a/pay-mall-trigger/src/main/java/edu/whut/trigger/job/NoPayNotifyOrderJob.java b/pay-mall-trigger/src/main/java/edu/whut/trigger/job/NoPayNotifyOrderJob.java index ad77585..4d60eca 100644 --- a/pay-mall-trigger/src/main/java/edu/whut/trigger/job/NoPayNotifyOrderJob.java +++ b/pay-mall-trigger/src/main/java/edu/whut/trigger/job/NoPayNotifyOrderJob.java @@ -25,7 +25,7 @@ public class NoPayNotifyOrderJob { private final AlipayClient alipayClient; /** - * 每3秒执行一次,扫描超过1分钟未收到回调的待支付订单 + * 每 3 秒执行一次,扫描超过1分钟未收到回调的待支付订单 */ @Scheduled(cron = "0/3 * * * * ?") public void exec() { @@ -46,12 +46,7 @@ public class NoPayNotifyOrderJob { String code = alipayTradeQueryResponse.getCode(); // 如果支付宝返回业务成功码(10000),则更新订单为支付成功 if ("10000".equals(code)) { - orderService.changeOrderPaySuccess(orderId); - }else { - log.warn("订单[{}]支付宝查询未成功:{}/{}", - orderId, - alipayTradeQueryResponse.getSubCode(), - alipayTradeQueryResponse.getSubMsg()); + orderService.changeOrderPaySuccess(orderId, alipayTradeQueryResponse.getSendPayDate()); } } } catch (Exception e) { diff --git a/pay-mall-trigger/src/main/java/edu/whut/trigger/job/TimeoutCloseOrderJob.java b/pay-mall-trigger/src/main/java/edu/whut/trigger/job/TimeoutCloseOrderJob.java index 4a91dca..6a59e63 100644 --- a/pay-mall-trigger/src/main/java/edu/whut/trigger/job/TimeoutCloseOrderJob.java +++ b/pay-mall-trigger/src/main/java/edu/whut/trigger/job/TimeoutCloseOrderJob.java @@ -20,7 +20,7 @@ public class TimeoutCloseOrderJob { /** * 每10分钟执行一次,扫描超时未支付订单 */ - @Scheduled(cron = "0 0/10 * * * ?") + @Scheduled(cron = "0 0/30 * * * ?") public void exec() { try { log.info("任务;超时30分钟订单关闭"); @@ -35,7 +35,7 @@ public class TimeoutCloseOrderJob { log.info("定时任务,超时30分钟订单关闭 orderId: {} status:{}", orderId, status); } } catch (Exception e) { - log.error("定时任务,超时15分钟订单关闭失败", e); + log.error("定时任务,超时30分钟订单关闭失败", e); } } diff --git a/pay-mall-trigger/src/main/java/edu/whut/trigger/listener/OrderPaySuccessListener.java b/pay-mall-trigger/src/main/java/edu/whut/trigger/listener/OrderPaySuccessListener.java index 1201338..e469e8a 100644 --- a/pay-mall-trigger/src/main/java/edu/whut/trigger/listener/OrderPaySuccessListener.java +++ b/pay-mall-trigger/src/main/java/edu/whut/trigger/listener/OrderPaySuccessListener.java @@ -1,6 +1,10 @@ package edu.whut.trigger.listener; +import com.alibaba.fastjson.JSON; import com.google.common.eventbus.Subscribe; +import edu.whut.domain.goods.service.IGoodsService; +import edu.whut.domain.order.adapter.event.PaySuccessMessageEvent; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -9,11 +13,20 @@ import org.springframework.stereotype.Component; */ @Slf4j @Component +@RequiredArgsConstructor public class OrderPaySuccessListener { + private final IGoodsService goodsService; @Subscribe - public void handleEvent(String paySuccessMessage) { - log.info("收到支付成功消息,可以做接下来的事情,如;发货、充值、开户员、返利 {}", paySuccessMessage); + public void handleEvent(String paySuccessMessageJson) { + log.info("收到支付成功消息 {}", paySuccessMessageJson); + + PaySuccessMessageEvent.PaySuccessMessage paySuccessMessage = JSON.parseObject(paySuccessMessageJson, PaySuccessMessageEvent.PaySuccessMessage.class); + + log.info("模拟发货(如;发货、充值、开户员、返利),单号:{}", paySuccessMessage.getTradeNo()); + + // 变更订单状态 - 发货完成&结算 + goodsService.changeOrderDealDone(paySuccessMessage.getTradeNo()); } }