diff --git a/group-buying-sys-app/src/main/resources/mybatis/mapper/notify_task_mapper.xml b/group-buying-sys-app/src/main/resources/mybatis/mapper/notify_task_mapper.xml
index 0203b51..8e9187f 100644
--- a/group-buying-sys-app/src/main/resources/mybatis/mapper/notify_task_mapper.xml
+++ b/group-buying-sys-app/src/main/resources/mybatis/mapper/notify_task_mapper.xml
@@ -20,9 +20,9 @@
insert into notify_task(
- activity_id, team_id, notify_type, notify_mq, notify_url, notify_count,
+ activity_id, team_id, notify_category, notify_type, notify_mq, notify_url, notify_count,
notify_status, parameter_json,uuid, create_time, update_time)
- values(#{activityId}, #{teamId}, #{notifyType}, #{notifyMQ}, #{notifyUrl},
+ values(#{activityId}, #{teamId}, #{notifyCategory}, #{notifyType}, #{notifyMQ}, #{notifyUrl},
#{notifyCount}, #{notifyStatus}, #{parameterJson},#{uuid},now(),now())
@@ -42,19 +42,19 @@
update notify_task
set notify_count = notify_count + 1, notify_status = 1, update_time = now()
- where team_id = #{teamId}
+ where team_id = #{teamId} and uuid = #{uuid}
update notify_task
set notify_count = notify_count + 1, notify_status = 3, update_time = now()
- where team_id = #{teamId}
+ where team_id = #{teamId} and uuid = #{uuid}
update notify_task
set notify_count = notify_count + 1, notify_status = 2, update_time = now()
- where team_id = #{teamId}
+ where team_id = #{teamId} and uuid = #{uuid}
diff --git a/group-buying-sys-app/src/test/java/edu/whut/test/domain/trade/ITradeReverseStockServiceTest.java b/group-buying-sys-app/src/test/java/edu/whut/test/domain/trade/ITradeReverseStockServiceTest.java
index febb07a..7c11713 100644
--- a/group-buying-sys-app/src/test/java/edu/whut/test/domain/trade/ITradeReverseStockServiceTest.java
+++ b/group-buying-sys-app/src/test/java/edu/whut/test/domain/trade/ITradeReverseStockServiceTest.java
@@ -19,6 +19,7 @@ import java.util.concurrent.CountDownLatch;
/**
* 锁单、恢复、锁单
+ * 测试退单流程:先下3单,再退一单,再下一单
*/
@Slf4j
@RunWith(SpringRunner.class)
@@ -34,8 +35,8 @@ public class ITradeReverseStockServiceTest {
@Test
public void test_refundOrder() throws Exception {
TradeRefundCommandEntity tradeRefundCommandEntity = TradeRefundCommandEntity.builder()
- .userId("smile11")
- .outTradeNo("690268736199")
+ .userId("smile21")
+ .outTradeNo("910878918962")
.source("s01")
.channel("c01")
.build();
@@ -54,7 +55,7 @@ public class ITradeReverseStockServiceTest {
String teamId = null;
for (int i = 1; i < 4; i++) {
LockMarketPayOrderRequestDTO lockMarketPayOrderRequestDTO = new LockMarketPayOrderRequestDTO();
- lockMarketPayOrderRequestDTO.setUserId("smile1" + i);
+ lockMarketPayOrderRequestDTO.setUserId("smile2" + i);
lockMarketPayOrderRequestDTO.setTeamId(teamId);
lockMarketPayOrderRequestDTO.setActivityId(100123L);
lockMarketPayOrderRequestDTO.setGoodsId("9890001");
@@ -74,8 +75,8 @@ public class ITradeReverseStockServiceTest {
@Test
public void test_lockMarketPayOrder_reverse() throws InterruptedException {
LockMarketPayOrderRequestDTO lockMarketPayOrderRequestDTO = new LockMarketPayOrderRequestDTO();
- lockMarketPayOrderRequestDTO.setUserId("smile14");
- lockMarketPayOrderRequestDTO.setTeamId("56790750");
+ lockMarketPayOrderRequestDTO.setUserId("smile24");
+ lockMarketPayOrderRequestDTO.setTeamId("68803511");
lockMarketPayOrderRequestDTO.setActivityId(100123L);
lockMarketPayOrderRequestDTO.setGoodsId("9890001");
lockMarketPayOrderRequestDTO.setSource("s01");
diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/adapter/repository/ITradeRepository.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/adapter/repository/ITradeRepository.java
index 6c2efb5..f77a2c8 100644
--- a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/adapter/repository/ITradeRepository.java
+++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/adapter/repository/ITradeRepository.java
@@ -36,11 +36,11 @@ public interface ITradeRepository {
List queryUnExecutedNotifyTaskList(String teamId);
- int updateNotifyTaskStatusSuccess(String teamId);
+ int updateNotifyTaskStatusSuccess(NotifyTaskEntity notifyTaskEntity);
- int updateNotifyTaskStatusError(String teamId);
+ int updateNotifyTaskStatusError(NotifyTaskEntity notifyTaskEntity);
- int updateNotifyTaskStatusRetry(String teamId);
+ int updateNotifyTaskStatusRetry(NotifyTaskEntity notifyTaskEntity);
boolean occupyTeamStock(String teamStockKey, String recoveryTeamStockKey, Integer target, Integer validTime);
diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/TradeRefundOrderService.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/TradeRefundOrderService.java
index 942d62c..d328b02 100644
--- a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/TradeRefundOrderService.java
+++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/TradeRefundOrderService.java
@@ -7,11 +7,14 @@ import edu.whut.domain.trade.model.valobj.TeamRefundSuccess;
import edu.whut.domain.trade.model.valobj.TradeOrderStatusEnumVO;
import edu.whut.domain.trade.service.ITradeRefundOrderService;
import edu.whut.domain.trade.service.refund.business.IRefundOrderStrategy;
+import edu.whut.domain.trade.service.refund.factory.TradeRefundRuleFilterFactory;
+import edu.whut.types.design.framework.link.model2.chain.BusinessLinkedList;
import edu.whut.types.enums.GroupBuyOrderStatusEnumVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
+import javax.annotation.Resource;
import java.util.Map;
/**
@@ -22,53 +25,24 @@ import java.util.Map;
@RequiredArgsConstructor
public class TradeRefundOrderService implements ITradeRefundOrderService {
- private final ITradeRepository repository;
//注入策略Map
private final Map refundOrderStrategyMap;
+ private final BusinessLinkedList tradeRefundRuleFilter;
+
+
+ /**
+ * 用户点击退单主动触发=》更新数据库操(锁单量、完成量、退款、拼团状态、订单状态...)
+ */
@Override
public TradeRefundBehaviorEntity refundOrder(TradeRefundCommandEntity tradeRefundCommandEntity) throws Exception {
log.info("逆向流程,退单操作 userId:{} outTradeNo:{}", tradeRefundCommandEntity.getUserId(), tradeRefundCommandEntity.getOutTradeNo());
-
- // 1. 查询外部交易单,组队id、orderId、拼团状态
- MarketPayOrderEntity marketPayOrderEntity = repository.queryMarketPayOrderEntityByOutTradeNo(tradeRefundCommandEntity.getUserId(), tradeRefundCommandEntity.getOutTradeNo());
- TradeOrderStatusEnumVO tradeOrderStatusEnumVO = marketPayOrderEntity.getTradeOrderStatusEnumVO();
- String teamId = marketPayOrderEntity.getTeamId();
- String orderId = marketPayOrderEntity.getOrderId();
-
- // 返回幂等,已完成退单
- if (TradeOrderStatusEnumVO.CLOSE.equals(tradeOrderStatusEnumVO)) {
- log.info("逆向流程,退单操作(幂等-重复退单) userId:{} outTradeNo:{}", tradeRefundCommandEntity.getUserId(), tradeRefundCommandEntity.getOutTradeNo());
- return TradeRefundBehaviorEntity.builder()
- .userId(tradeRefundCommandEntity.getUserId())
- .orderId(orderId)
- .teamId(teamId)
- .tradeRefundBehaviorEnum(TradeRefundBehaviorEntity.TradeRefundBehaviorEnum.REPEAT)
- .build();
- }
-
- // 2. 查询拼团状态
- GroupBuyTeamEntity groupBuyTeamEntity = repository.queryGroupBuyTeamByTeamId(teamId);
- GroupBuyOrderStatusEnumVO groupBuyOrderStatusEnumVO = groupBuyTeamEntity.getStatus();
-
- // 3. 根据拼团状态和交易状态判断退单类型 -> 判断使用哪种策略模式
- RefundTypeEnumVO refundType = RefundTypeEnumVO.getRefundStrategy(groupBuyOrderStatusEnumVO, tradeOrderStatusEnumVO);
- IRefundOrderStrategy refundOrderStrategy = refundOrderStrategyMap.get(refundType.getStrategy());
- refundOrderStrategy.refundOrder(TradeRefundOrderEntity.builder()
- .userId(tradeRefundCommandEntity.getUserId())
- .orderId(orderId)
- .teamId(teamId)
- .activityId(groupBuyTeamEntity.getActivityId())
- .build());
-
- return TradeRefundBehaviorEntity.builder()
- .userId(tradeRefundCommandEntity.getUserId())
- .orderId(orderId)
- .teamId(teamId)
- .tradeRefundBehaviorEnum(TradeRefundBehaviorEntity.TradeRefundBehaviorEnum.SUCCESS)
- .build();
+ return tradeRefundRuleFilter.apply(tradeRefundCommandEntity, new TradeRefundRuleFilterFactory.DynamicContext());
}
+ /**
+ * 退单成功后,消息监听触发-》恢复锁单量
+ */
@Override
public void restoreTeamLockStock(TeamRefundSuccess teamRefundSuccess) throws Exception {
log.info("逆向流程,恢复锁单量 userId:{} activityId:{} teamId:{}", teamRefundSuccess.getUserId(), teamRefundSuccess.getActivityId(), teamRefundSuccess.getTeamId());
diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/business/AbstractRefundOrderStrategy.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/business/AbstractRefundOrderStrategy.java
new file mode 100644
index 0000000..85b51c3
--- /dev/null
+++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/business/AbstractRefundOrderStrategy.java
@@ -0,0 +1,68 @@
+package edu.whut.domain.trade.service.refund.business;
+
+import com.alibaba.fastjson.JSON;
+import edu.whut.domain.trade.adapter.repository.ITradeRepository;
+import edu.whut.domain.trade.model.entity.NotifyTaskEntity;
+import edu.whut.domain.trade.model.valobj.TeamRefundSuccess;
+import edu.whut.domain.trade.service.ITradeTaskService;
+import edu.whut.domain.trade.service.lock.factory.TradeLockRuleFilterFactory;
+import edu.whut.types.exception.AppException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.annotation.Resource;
+import java.util.Map;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * 退单策略抽象基类
+ * 提供共用的依赖注入和MQ消息发送功能
+ */
+@Slf4j
+@RequiredArgsConstructor
+public abstract class AbstractRefundOrderStrategy implements IRefundOrderStrategy {
+
+ @Resource
+ protected ITradeRepository repository;
+
+ @Resource
+ protected ITradeTaskService tradeTaskService;
+
+ @Resource
+ protected ThreadPoolExecutor threadPoolExecutor;
+
+ /**
+ * 异步发送MQ消息
+ * @param notifyTaskEntity 通知任务实体
+ * @param refundType 退单类型描述
+ */
+ protected void sendRefundNotifyMessage(NotifyTaskEntity notifyTaskEntity, String refundType) {
+ if (null != notifyTaskEntity) {
+ threadPoolExecutor.execute(() -> {
+ Map notifyResultMap = null;
+ try {
+ notifyResultMap = tradeTaskService.execNotifyJob(notifyTaskEntity);
+ log.info("回调通知交易退单({}) result:{}", refundType, JSON.toJSONString(notifyResultMap));
+ } catch (Exception e) {
+ log.error("回调通知交易退单失败({}) result:{}", refundType, JSON.toJSONString(notifyResultMap), e);
+ throw new AppException(e.getMessage());
+ }
+ });
+ }
+ }
+
+ /**
+ * 通用库存恢复逻辑
+ * @param teamRefundSuccess 团队退单成功信息
+ * @param refundType 退单类型描述
+ * @throws Exception 异常
+ */
+ protected void doReverseStock(TeamRefundSuccess teamRefundSuccess, String refundType) throws Exception {
+ log.info("退单;恢复锁单量 - {} {} {} {}", refundType, teamRefundSuccess.getUserId(), teamRefundSuccess.getActivityId(), teamRefundSuccess.getTeamId());
+ // 1. 恢复库存key
+ String recoveryTeamStockKey = TradeLockRuleFilterFactory.generateRecoveryTeamStockKey(teamRefundSuccess.getActivityId(), teamRefundSuccess.getTeamId());
+ // 2. 退单恢复库存
+ repository.refund2AddRecovery(recoveryTeamStockKey, teamRefundSuccess.getOrderId());
+ }
+
+}
\ No newline at end of file
diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/business/impl/Paid2RefundStrategy.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/business/impl/Paid2RefundStrategy.java
index d96fff2..e00c744 100644
--- a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/business/impl/Paid2RefundStrategy.java
+++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/business/impl/Paid2RefundStrategy.java
@@ -1,21 +1,12 @@
package edu.whut.domain.trade.service.refund.business.impl;
-
-import com.alibaba.fastjson.JSON;
-import edu.whut.domain.trade.adapter.port.ITradePort;
-import edu.whut.domain.trade.adapter.repository.ITradeRepository;
import edu.whut.domain.trade.model.aggregate.GroupBuyRefundAggregate;
import edu.whut.domain.trade.model.entity.NotifyTaskEntity;
import edu.whut.domain.trade.model.entity.TradeRefundOrderEntity;
import edu.whut.domain.trade.model.valobj.TeamRefundSuccess;
-import edu.whut.domain.trade.service.ITradeTaskService;
-import edu.whut.domain.trade.service.lock.factory.TradeLockRuleFilterFactory;
-import edu.whut.domain.trade.service.refund.business.IRefundOrderStrategy;
-import edu.whut.types.exception.AppException;
+import edu.whut.domain.trade.service.refund.business.AbstractRefundOrderStrategy;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
-import java.util.Map;
-import java.util.concurrent.ThreadPoolExecutor;
/**
* 发起退单(未成团&已支付),锁单量-1、完成量-1、组队订单状态更新、发送退单消息(MQ)
@@ -23,13 +14,7 @@ import java.util.concurrent.ThreadPoolExecutor;
@Slf4j
@Service("paid2RefundStrategy")
@RequiredArgsConstructor
-public class Paid2RefundStrategy implements IRefundOrderStrategy {
-
- private final ITradeRepository repository;
-
- private final ITradeTaskService tradeTaskService;
-
- private final ThreadPoolExecutor threadPoolExecutor;
+public class Paid2RefundStrategy extends AbstractRefundOrderStrategy {
@Override
public void refundOrder(TradeRefundOrderEntity tradeRefundOrderEntity) throws Exception {
@@ -38,27 +23,12 @@ public class Paid2RefundStrategy implements IRefundOrderStrategy {
// 1. 退单,已支付&未成团
NotifyTaskEntity notifyTaskEntity = repository.paid2Refund(GroupBuyRefundAggregate.buildPaid2RefundAggregate(tradeRefundOrderEntity, -1, -1));
- // 2. 发送MQ消息
- if (null != notifyTaskEntity) {
- threadPoolExecutor.execute(() -> {
- Map notifyResultMap = null;
- try {
- notifyResultMap = tradeTaskService.execNotifyJob(notifyTaskEntity);
- log.info("回调通知交易退单(已支付,未成团) result:{}", JSON.toJSONString(notifyResultMap));
- } catch (Exception e) {
- log.error("回调通知交易退单失败(已支付,未成团) result:{}", JSON.toJSONString(notifyResultMap), e);
- throw new AppException(e.getMessage());
- }
- });
- }
+ // 2. 发送MQ消息 - 发送MQ,恢复锁单库存量使用
+ sendRefundNotifyMessage(notifyTaskEntity, "已支付,未成团");
}
@Override
public void reverseStock(TeamRefundSuccess teamRefundSuccess) throws Exception {
- log.info("退单;恢复锁单量 - 已支付,未成团,但有锁单记录,要恢复锁单库存 {} {} {}", teamRefundSuccess.getUserId(), teamRefundSuccess.getActivityId(), teamRefundSuccess.getTeamId());
- // 1. 恢复库存key
- String recoveryTeamStockKey = TradeLockRuleFilterFactory.generateRecoveryTeamStockKey(teamRefundSuccess.getActivityId(), teamRefundSuccess.getTeamId());
- // 2. 退单恢复「已支付,未成团,有锁单记录,要恢复锁单库存」
- repository.refund2AddRecovery(recoveryTeamStockKey, teamRefundSuccess.getOrderId());
+ doReverseStock(teamRefundSuccess, "已支付,未成团,但有锁单记录,要恢复锁单库存");
}
}
diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/business/impl/PaidTeam2RefundStrategy.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/business/impl/PaidTeam2RefundStrategy.java
index 6cc5f37..d0b84a8 100644
--- a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/business/impl/PaidTeam2RefundStrategy.java
+++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/business/impl/PaidTeam2RefundStrategy.java
@@ -1,21 +1,15 @@
package edu.whut.domain.trade.service.refund.business.impl;
-import com.alibaba.fastjson.JSON;
-import edu.whut.domain.trade.adapter.repository.ITradeRepository;
import edu.whut.domain.trade.model.aggregate.GroupBuyRefundAggregate;
import edu.whut.domain.trade.model.entity.GroupBuyTeamEntity;
import edu.whut.domain.trade.model.entity.NotifyTaskEntity;
import edu.whut.domain.trade.model.entity.TradeRefundOrderEntity;
import edu.whut.domain.trade.model.valobj.TeamRefundSuccess;
-import edu.whut.domain.trade.service.ITradeTaskService;
-import edu.whut.domain.trade.service.refund.business.IRefundOrderStrategy;
+import edu.whut.domain.trade.service.refund.business.AbstractRefundOrderStrategy;
import edu.whut.types.enums.GroupBuyOrderStatusEnumVO;
-import edu.whut.types.exception.AppException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
-import java.util.Map;
-import java.util.concurrent.ThreadPoolExecutor;
/**
* 发起退单(已成团&已支付),锁单量-1、完成量-1、组队订单状态更新、发送退单消息(MQ)
@@ -23,41 +17,23 @@ import java.util.concurrent.ThreadPoolExecutor;
@Slf4j
@Service("paidTeam2RefundStrategy")
@RequiredArgsConstructor
-public class PaidTeam2RefundStrategy implements IRefundOrderStrategy {
-
- private final ITradeRepository repository;
-
- private final ITradeTaskService tradeTaskService;
-
- private final ThreadPoolExecutor threadPoolExecutor;
+public class PaidTeam2RefundStrategy extends AbstractRefundOrderStrategy {
@Override
public void refundOrder(TradeRefundOrderEntity tradeRefundOrderEntity) {
log.info("退单;已支付,已成团 userId:{} teamId:{} orderId:{}", tradeRefundOrderEntity.getUserId(), tradeRefundOrderEntity.getTeamId(), tradeRefundOrderEntity.getOrderId());
GroupBuyTeamEntity groupBuyTeamEntity = repository.queryGroupBuyTeamByTeamId(tradeRefundOrderEntity.getTeamId());
- // 当前拼团完成量
Integer completeCount = groupBuyTeamEntity.getCompleteCount();
- // 该拼团中最后一个用户也要退单,则更新拼团订单为失败
+ // 最后一笔也退单,则更新拼团订单为失败
GroupBuyOrderStatusEnumVO groupBuyOrderEnumVO = 1 == completeCount ? GroupBuyOrderStatusEnumVO.FAIL : GroupBuyOrderStatusEnumVO.COMPLETE_FAIL;
// 1. 退单,已支付&已成团
NotifyTaskEntity notifyTaskEntity = repository.paidTeam2Refund(GroupBuyRefundAggregate.buildPaidTeam2RefundAggregate(tradeRefundOrderEntity, -1, -1, groupBuyOrderEnumVO));
- // 2. 发送MQ消息
- if (null != notifyTaskEntity) {
- threadPoolExecutor.execute(() -> {
- Map notifyResultMap = null;
- try {
- notifyResultMap = tradeTaskService.execNotifyJob(notifyTaskEntity);
- log.info("回调通知交易退单(已支付,已成团) result:{}", JSON.toJSONString(notifyResultMap));
- } catch (Exception e) {
- log.error("回调通知交易退单失败(已支付,已成团) result:{}", JSON.toJSONString(notifyResultMap), e);
- throw new AppException(e.getMessage());
- }
- });
- }
+ // 2. 发送MQ消息 - 发送MQ,恢复锁单库存量使用
+ sendRefundNotifyMessage(notifyTaskEntity, "已支付,已成团");
}
@Override
public void reverseStock(TeamRefundSuccess teamRefundSuccess) throws Exception {
diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/business/impl/Unpaid2RefundStrategy.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/business/impl/Unpaid2RefundStrategy.java
index 83b6c93..4f7fa13 100644
--- a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/business/impl/Unpaid2RefundStrategy.java
+++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/business/impl/Unpaid2RefundStrategy.java
@@ -1,22 +1,14 @@
package edu.whut.domain.trade.service.refund.business.impl;
-import com.alibaba.fastjson.JSON;
-import edu.whut.domain.trade.adapter.repository.ITradeRepository;
import edu.whut.domain.trade.model.aggregate.GroupBuyRefundAggregate;
import edu.whut.domain.trade.model.entity.NotifyTaskEntity;
import edu.whut.domain.trade.model.entity.TradeRefundOrderEntity;
import edu.whut.domain.trade.model.valobj.TeamRefundSuccess;
-import edu.whut.domain.trade.service.ITradeTaskService;
-import edu.whut.domain.trade.service.lock.factory.TradeLockRuleFilterFactory;
-import edu.whut.domain.trade.service.refund.business.IRefundOrderStrategy;
-import edu.whut.types.exception.AppException;
+import edu.whut.domain.trade.service.refund.business.AbstractRefundOrderStrategy;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
-import javax.annotation.Resource;
-import java.util.Map;
-import java.util.concurrent.ThreadPoolExecutor;
/**
* 未支付,未成团;发起退单(未支付),锁单量-1、组队订单状态更新
@@ -24,13 +16,7 @@ import java.util.concurrent.ThreadPoolExecutor;
@Slf4j
@Service("unpaid2RefundStrategy")
@RequiredArgsConstructor
-public class Unpaid2RefundStrategy implements IRefundOrderStrategy {
-
- private final ITradeRepository repository;
-
- private final ITradeTaskService tradeTaskService;
-
- private final ThreadPoolExecutor threadPoolExecutor;
+public class Unpaid2RefundStrategy extends AbstractRefundOrderStrategy {
/**
* 用户未支付的退单流程,仅需更新订单状态为已退单,释放lockcount锁单量
@@ -42,27 +28,12 @@ public class Unpaid2RefundStrategy implements IRefundOrderStrategy {
NotifyTaskEntity notifyTaskEntity = repository.unpaid2Refund(GroupBuyRefundAggregate.buildUnpaid2RefundAggregate(tradeRefundOrderEntity, -1));
// 2. 发送MQ消息 - 发送MQ,恢复锁单库存量使用
- if (null != notifyTaskEntity) {
- threadPoolExecutor.execute(() -> {
- Map notifyResultMap = null;
- try {
- notifyResultMap = tradeTaskService.execNotifyJob(notifyTaskEntity);
- log.info("回调通知交易退单(未支付,未成团) result:{}", JSON.toJSONString(notifyResultMap));
- } catch (Exception e) {
- log.error("回调通知交易退单失败(未支付,未成团) result:{}", JSON.toJSONString(notifyResultMap), e);
- throw new AppException(e.getMessage());
- }
- });
- }
+ sendRefundNotifyMessage(notifyTaskEntity, "未支付,未成团");
}
@Override
public void reverseStock(TeamRefundSuccess teamRefundSuccess) throws Exception {
- log.info("退单;恢复锁单量 - 未支付,未成团,但有锁单记录,要恢复锁单库存 {} {} {}", teamRefundSuccess.getUserId(), teamRefundSuccess.getActivityId(), teamRefundSuccess.getTeamId());
- // 1. 恢复库存key
- String recoveryTeamStockKey = TradeLockRuleFilterFactory.generateRecoveryTeamStockKey(teamRefundSuccess.getActivityId(), teamRefundSuccess.getTeamId());
- // 2. 退单恢复「未支付,未成团,但有锁单记录,要恢复锁单库存」
- repository.refund2AddRecovery(recoveryTeamStockKey, teamRefundSuccess.getOrderId());
+ doReverseStock(teamRefundSuccess, "未支付,未成团,但有锁单记录,要恢复锁单库存");
}
}
diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/factory/TradeRefundRuleFilterFactory.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/factory/TradeRefundRuleFilterFactory.java
new file mode 100644
index 0000000..276a470
--- /dev/null
+++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/factory/TradeRefundRuleFilterFactory.java
@@ -0,0 +1,55 @@
+package edu.whut.domain.trade.service.refund.factory;
+import edu.whut.domain.trade.model.entity.GroupBuyTeamEntity;
+import edu.whut.domain.trade.model.entity.MarketPayOrderEntity;
+import edu.whut.domain.trade.model.entity.TradeRefundBehaviorEntity;
+import edu.whut.domain.trade.model.entity.TradeRefundCommandEntity;
+import edu.whut.domain.trade.service.refund.filter.DataNodeFilter;
+import edu.whut.domain.trade.service.refund.filter.RefundOrderNodeFilter;
+import edu.whut.domain.trade.service.refund.filter.UniqueRefundNodeFilter;
+import edu.whut.types.design.framework.link.model2.LinkArmory;
+import edu.whut.types.design.framework.link.model2.chain.BusinessLinkedList;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Service;
+
+/**
+ * 交易退单工程
+ */
+@Slf4j
+@Service
+public class TradeRefundRuleFilterFactory {
+
+ @Bean("tradeRefundRuleFilter")
+ public BusinessLinkedList tradeRefundRuleFilter(
+ DataNodeFilter dataNodeFilter,
+ UniqueRefundNodeFilter uniqueRefundNodeFilter,
+ RefundOrderNodeFilter refundOrderNodeFilter) {
+
+ // 组装链
+ LinkArmory linkArmory =
+ new LinkArmory<>("退单规则过滤链",
+ dataNodeFilter,
+ uniqueRefundNodeFilter,
+ refundOrderNodeFilter);
+
+ // 链对象
+ return linkArmory.getLogicLink();
+ }
+
+ @Data
+ @Builder
+ @AllArgsConstructor
+ @NoArgsConstructor
+ public static class DynamicContext {
+
+ private MarketPayOrderEntity marketPayOrderEntity;
+
+ private GroupBuyTeamEntity groupBuyTeamEntity;
+
+ }
+
+}
diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/filter/DataNodeFilter.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/filter/DataNodeFilter.java
new file mode 100644
index 0000000..31cca66
--- /dev/null
+++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/filter/DataNodeFilter.java
@@ -0,0 +1,45 @@
+package edu.whut.domain.trade.service.refund.filter;
+
+
+import edu.whut.domain.trade.adapter.repository.ITradeRepository;
+import edu.whut.domain.trade.model.entity.GroupBuyTeamEntity;
+import edu.whut.domain.trade.model.entity.MarketPayOrderEntity;
+import edu.whut.domain.trade.model.entity.TradeRefundBehaviorEntity;
+import edu.whut.domain.trade.model.entity.TradeRefundCommandEntity;
+import edu.whut.domain.trade.service.refund.factory.TradeRefundRuleFilterFactory;
+import edu.whut.types.design.framework.link.model2.handler.ILogicHandler;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+/**
+ * 数据节点
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class DataNodeFilter implements ILogicHandler {
+
+ private final ITradeRepository repository;
+
+ @Override
+ public TradeRefundBehaviorEntity apply(TradeRefundCommandEntity tradeRefundCommandEntity, TradeRefundRuleFilterFactory.DynamicContext dynamicContext) throws Exception {
+ log.info("逆向流程-退单操作,数据加载节点 userId:{} outTradeNo:{}", tradeRefundCommandEntity.getUserId(), tradeRefundCommandEntity.getOutTradeNo());
+
+ // 1. 查询外部交易单,组队id、orderId、拼团状态
+ MarketPayOrderEntity marketPayOrderEntity = repository.queryMarketPayOrderEntityByOutTradeNo(tradeRefundCommandEntity.getUserId(), tradeRefundCommandEntity.getOutTradeNo());
+ String teamId = marketPayOrderEntity.getTeamId();
+
+ // 2. 查询拼团状态
+ GroupBuyTeamEntity groupBuyTeamEntity = repository.queryGroupBuyTeamByTeamId(teamId);
+
+ // 3. 写入上下文;如果查询数据是比较多的,可以参考 MarketNode2CompletableFuture 通过多线程进行加载
+ dynamicContext.setMarketPayOrderEntity(marketPayOrderEntity);
+ dynamicContext.setGroupBuyTeamEntity(groupBuyTeamEntity);
+
+ return next(tradeRefundCommandEntity, dynamicContext);
+ }
+
+}
diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/filter/RefundOrderNodeFilter.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/filter/RefundOrderNodeFilter.java
new file mode 100644
index 0000000..4efa17a
--- /dev/null
+++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/filter/RefundOrderNodeFilter.java
@@ -0,0 +1,58 @@
+package edu.whut.domain.trade.service.refund.filter;
+
+import edu.whut.domain.trade.model.entity.*;
+import edu.whut.domain.trade.model.valobj.RefundTypeEnumVO;
+import edu.whut.domain.trade.model.valobj.TradeOrderStatusEnumVO;
+import edu.whut.domain.trade.service.refund.business.IRefundOrderStrategy;
+import edu.whut.domain.trade.service.refund.factory.TradeRefundRuleFilterFactory;
+import edu.whut.types.design.framework.link.model2.handler.ILogicHandler;
+import edu.whut.types.enums.GroupBuyOrderStatusEnumVO;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Map;
+
+/**
+ * 退单节点
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class RefundOrderNodeFilter implements ILogicHandler {
+
+ //依赖注入:策略选择map
+ private final Map refundOrderStrategyMap;
+
+ @Override
+ public TradeRefundBehaviorEntity apply(TradeRefundCommandEntity tradeRefundCommandEntity, TradeRefundRuleFilterFactory.DynamicContext dynamicContext) throws Exception {
+ log.info("逆向流程-退单操作,退单策略处理 userId:{} outTradeNo:{}", tradeRefundCommandEntity.getUserId(), tradeRefundCommandEntity.getOutTradeNo());
+
+ // 上下文数据
+ MarketPayOrderEntity marketPayOrderEntity = dynamicContext.getMarketPayOrderEntity();
+ TradeOrderStatusEnumVO tradeOrderStatusEnumVO = marketPayOrderEntity.getTradeOrderStatusEnumVO();
+
+ GroupBuyTeamEntity groupBuyTeamEntity = dynamicContext.getGroupBuyTeamEntity();
+ GroupBuyOrderStatusEnumVO groupBuyOrderEnumVO = groupBuyTeamEntity.getStatus();
+
+ // 获取执行策略
+ RefundTypeEnumVO refundType = RefundTypeEnumVO.getRefundStrategy(groupBuyOrderEnumVO, tradeOrderStatusEnumVO);
+ IRefundOrderStrategy refundOrderStrategy = refundOrderStrategyMap.get(refundType.getStrategy());
+
+ // 执行退单操作
+ refundOrderStrategy.refundOrder(TradeRefundOrderEntity.builder()
+ .userId(tradeRefundCommandEntity.getUserId())
+ .orderId(marketPayOrderEntity.getOrderId())
+ .teamId(marketPayOrderEntity.getTeamId())
+ .activityId(groupBuyTeamEntity.getActivityId())
+ .build());
+
+ return TradeRefundBehaviorEntity.builder()
+ .userId(tradeRefundCommandEntity.getUserId())
+ .orderId(marketPayOrderEntity.getOrderId())
+ .teamId(marketPayOrderEntity.getTeamId())
+ .tradeRefundBehaviorEnum(TradeRefundBehaviorEntity.TradeRefundBehaviorEnum.SUCCESS)
+ .build();
+ }
+}
diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/filter/UniqueRefundNodeFilter.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/filter/UniqueRefundNodeFilter.java
new file mode 100644
index 0000000..f640ca1
--- /dev/null
+++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/refund/filter/UniqueRefundNodeFilter.java
@@ -0,0 +1,40 @@
+package edu.whut.domain.trade.service.refund.filter;
+
+import edu.whut.domain.trade.model.entity.MarketPayOrderEntity;
+import edu.whut.domain.trade.model.entity.TradeRefundBehaviorEntity;
+import edu.whut.domain.trade.model.entity.TradeRefundCommandEntity;
+import edu.whut.domain.trade.model.valobj.TradeOrderStatusEnumVO;
+import edu.whut.domain.trade.service.refund.factory.TradeRefundRuleFilterFactory;
+import edu.whut.types.design.framework.link.model2.handler.ILogicHandler;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * 重复退单检查
+ */
+@Slf4j
+@Service
+public class UniqueRefundNodeFilter implements ILogicHandler {
+
+ @Override
+ public TradeRefundBehaviorEntity apply(TradeRefundCommandEntity tradeRefundCommandEntity, TradeRefundRuleFilterFactory.DynamicContext dynamicContext) throws Exception {
+ log.info("逆向流程-退单操作,重复退单检查 userId:{} outTradeNo:{}", tradeRefundCommandEntity.getUserId(), tradeRefundCommandEntity.getOutTradeNo());
+
+ MarketPayOrderEntity marketPayOrderEntity = dynamicContext.getMarketPayOrderEntity();
+ TradeOrderStatusEnumVO tradeOrderStatusEnumVO = marketPayOrderEntity.getTradeOrderStatusEnumVO();
+
+ // 返回幂等,已完成退单
+ if (TradeOrderStatusEnumVO.CLOSE.equals(tradeOrderStatusEnumVO)) {
+ log.info("逆向流程,退单操作(幂等-重复退单) userId:{} outTradeNo:{}", tradeRefundCommandEntity.getUserId(), tradeRefundCommandEntity.getOutTradeNo());
+ return TradeRefundBehaviorEntity.builder()
+ .userId(tradeRefundCommandEntity.getUserId())
+ .orderId(marketPayOrderEntity.getOrderId())
+ .teamId(marketPayOrderEntity.getTeamId())
+ .tradeRefundBehaviorEnum(TradeRefundBehaviorEntity.TradeRefundBehaviorEnum.REPEAT)
+ .build();
+ }
+
+ return next(tradeRefundCommandEntity, dynamicContext);
+ }
+
+}
diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/task/TradeTaskService.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/task/TradeTaskService.java
index ca8e3cc..8fec894 100644
--- a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/task/TradeTaskService.java
+++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/task/TradeTaskService.java
@@ -64,8 +64,7 @@ public class TradeTaskService implements ITradeTaskService {
/**
* 公共逻辑抽取:遍历任务列表,调用外部服务,更新数据库并计数
- * @param notifyTaskEntityList 待处理的通知任务列表
- * @return key——任务总量、successCount、errorCount、retryCount
+ * 拼团成功消息 or 退单消息
*/
private Map execNotifyJob(List notifyTaskEntityList) throws Exception {
//successCount:成功回调的任务数量
@@ -76,19 +75,19 @@ public class TradeTaskService implements ITradeTaskService {
// 更新状态判断&变更数据库表回调任务状态
if (NotifyTaskHTTPEnumVO.SUCCESS.getCode().equals(response)) {
- int updateCount = repository.updateNotifyTaskStatusSuccess(notifyTask.getTeamId());
+ int updateCount = repository.updateNotifyTaskStatusSuccess(notifyTask);
if (1 == updateCount) {
successCount += 1;
}
} else if (NotifyTaskHTTPEnumVO.ERROR.getCode().equals(response)) {
if (notifyTask.getNotifyCount() < 5) {
// 失败但可以重试 → 标记为 RETRY,等待下一次收集 “待处理的通知任务列表”
- if (repository.updateNotifyTaskStatusRetry(notifyTask.getTeamId()) == 1) {
+ if (repository.updateNotifyTaskStatusRetry(notifyTask) == 1) {
retryCount++;
}
} else {
// 已达最大重试次数 → 标记为 ERROR(不再重试)
- if (repository.updateNotifyTaskStatusError(notifyTask.getTeamId()) == 1) {
+ if (repository.updateNotifyTaskStatusError(notifyTask) == 1) {
errorCount++;
}
}
diff --git a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/TradeRepository.java b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/TradeRepository.java
index 4afcf95..347cdf0 100644
--- a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/TradeRepository.java
+++ b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/TradeRepository.java
@@ -309,8 +309,8 @@ public class TradeRepository implements ITradeRepository {
NotifyTask task = new NotifyTask();
task.setActivityId(team.getActivityId());
task.setTeamId(team.getTeamId());
- task.setNotifyCategory(TaskNotifyCategoryEnumVO.TRADE_SETTLEMENT.getCode());
- task.setNotifyType(notifyConfigVO.getNotifyType().getCode());
+ task.setNotifyCategory(TaskNotifyCategoryEnumVO.TRADE_SETTLEMENT.getCode()); //拼团成团消息
+ task.setNotifyType(notifyConfigVO.getNotifyType().getCode()); //HTTP or MQ
task.setNotifyMQ(NotifyTypeEnumVO.MQ.equals(notifyConfigVO.getNotifyType()) ? notifyConfigVO.getNotifyMQ() : null);
task.setNotifyUrl(NotifyTypeEnumVO.HTTP.equals(notifyConfigVO.getNotifyType()) ? notifyConfigVO.getNotifyUrl() : null);
task.setNotifyCount(0);
@@ -386,6 +386,7 @@ public class TradeRepository implements ITradeRepository {
.notifyUrl(notifyTask.getNotifyUrl())
.notifyCount(notifyTask.getNotifyCount())
.parameterJson(notifyTask.getParameterJson())
+ .uuid(notifyTask.getUuid())
.build());
}
@@ -393,24 +394,36 @@ public class TradeRepository implements ITradeRepository {
* 更新指定 teamId 的通知任务状态为成功
*/
@Override
- public int updateNotifyTaskStatusSuccess(String teamId) {
- return notifyTaskDao.updateNotifyTaskStatusSuccess(teamId);
+ public int updateNotifyTaskStatusSuccess(NotifyTaskEntity notifyTaskEntity) {
+ NotifyTask notifyTask = NotifyTask.builder()
+ .teamId(notifyTaskEntity.getTeamId())
+ .uuid(notifyTaskEntity.getUuid())
+ .build();
+ return notifyTaskDao.updateNotifyTaskStatusSuccess(notifyTask);
}
/**
* 更新指定 teamId 的通知任务状态为失败(不可重试)
*/
@Override
- public int updateNotifyTaskStatusError(String teamId) {
- return notifyTaskDao.updateNotifyTaskStatusError(teamId);
+ public int updateNotifyTaskStatusError(NotifyTaskEntity notifyTaskEntity) {
+ NotifyTask notifyTask = NotifyTask.builder()
+ .teamId(notifyTaskEntity.getTeamId())
+ .uuid(notifyTaskEntity.getUuid())
+ .build();
+ return notifyTaskDao.updateNotifyTaskStatusError(notifyTask);
}
/**
* 更新指定 teamId 的通知任务状态为重试
*/
@Override
- public int updateNotifyTaskStatusRetry(String teamId) {
- return notifyTaskDao.updateNotifyTaskStatusRetry(teamId);
+ public int updateNotifyTaskStatusRetry(NotifyTaskEntity notifyTaskEntity) {
+ NotifyTask notifyTask = NotifyTask.builder()
+ .teamId(notifyTaskEntity.getTeamId())
+ .uuid(notifyTaskEntity.getUuid())
+ .build();
+ return notifyTaskDao.updateNotifyTaskStatusRetry(notifyTask);
}
/**
diff --git a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/INotifyTaskDao.java b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/INotifyTaskDao.java
index 95d955c..8e84055 100644
--- a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/INotifyTaskDao.java
+++ b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/INotifyTaskDao.java
@@ -16,10 +16,10 @@ public interface INotifyTaskDao {
NotifyTask queryUnExecutedNotifyTaskByTeamId(String teamId);
- int updateNotifyTaskStatusSuccess(String teamId);
+ int updateNotifyTaskStatusSuccess(NotifyTask notifyTask);
- int updateNotifyTaskStatusError(String teamId);
+ int updateNotifyTaskStatusError(NotifyTask notifyTask);
- int updateNotifyTaskStatusRetry(String teamId);
+ int updateNotifyTaskStatusRetry(NotifyTask notifyTask);
}