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', 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', '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', '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', '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());
}
}