From ca9faa403b0d360362bb1e69ec6e7d0d419fa088 Mon Sep 17 00:00:00 2001 From: zhangsan <646228430@qq.com> Date: Wed, 2 Jul 2025 19:49:10 +0800 Subject: [PATCH] =?UTF-8?q?7.2=20=E6=94=AF=E4=BB=98=E6=88=90=E5=8A=9F?= =?UTF-8?q?=E5=90=8E=E5=9B=9E=E8=B0=83=E5=8A=9F=E8=83=BD=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=EF=BC=8C=E6=9B=B4=E6=96=B0=E6=8B=BC=E5=9B=A2=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mysql/sql/0702group_buying_sys.sql | 2 +- .../mapper/group_buy_order_list_mapper.xml | 9 ++ .../mybatis/mapper/group_buy_order_mapper.xml | 19 ++++ .../mybatis/mapper/notify_task_mapper.xml | 23 +++++ ...t.java => ITradeLockOrderServiceTest.java} | 6 +- .../TradeSettlementOrderServiceTest.java | 38 ++++++++ .../trigger/MarketTradeControllerTest.java | 6 +- .../whut/domain/tag/service/TagService.java | 2 + .../adapter/repository/ITradeRepository.java | 7 ++ .../GroupBuyTeamSettlementAggregate.java | 26 +++++ .../model/entity/GroupBuyTeamEntity.java | 30 ++++++ .../model/entity/MarketPayOrderEntity.java | 2 + .../entity/TradePaySettlementEntity.java | 30 ++++++ .../model/entity/TradePaySuccessEntity.java | 26 +++++ ...rvice.java => ITradeLockOrderService.java} | 2 +- .../service/ITradeSettlementOrderService.java | 18 ++++ .../TradeLockLockOrderService.java} | 9 +- .../factory/TradeRuleFilterFactory.java | 6 +- .../filter/ActivityUsabilityRuleFilter.java | 5 +- .../filter/UserTakeLimitRuleFilter.java | 4 +- .../TradeSettlementOrderService.java | 60 ++++++++++++ .../adapter/repository/TradeRepository.java | 96 ++++++++++++++++++- .../infrastructure/dao/IGroupBuyOrderDao.java | 6 ++ .../dao/IGroupBuyOrderListDao.java | 7 ++ .../infrastructure/dao/INotifyTaskDao.java | 13 +++ .../infrastructure/dao/po/NotifyTask.java | 37 +++++++ .../trigger/http/MarketTradeController.java | 4 +- .../enums/GroupBuyOrderStatusEnumVO.java | 35 +++++++ .../edu/whut/types/enums/ResponseCode.java | 2 + 29 files changed, 507 insertions(+), 23 deletions(-) create mode 100644 group-buying-sys-app/src/main/resources/mybatis/mapper/notify_task_mapper.xml rename group-buying-sys-app/src/test/java/edu/whut/test/domain/trade/{ITradeOrderServiceTest.java => ITradeLockOrderServiceTest.java} (95%) create mode 100644 group-buying-sys-app/src/test/java/edu/whut/test/domain/trade/TradeSettlementOrderServiceTest.java create mode 100644 group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/aggregate/GroupBuyTeamSettlementAggregate.java create mode 100644 group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/GroupBuyTeamEntity.java create mode 100644 group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/TradePaySettlementEntity.java create mode 100644 group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/TradePaySuccessEntity.java rename group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/{ITradeOrderService.java => ITradeLockOrderService.java} (96%) create mode 100644 group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/ITradeSettlementOrderService.java rename group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/{TradeOrderService.java => lock/TradeLockLockOrderService.java} (90%) rename group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/{ => lock}/factory/TradeRuleFilterFactory.java (89%) rename group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/{ => lock}/filter/ActivityUsabilityRuleFilter.java (94%) rename group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/{ => lock}/filter/UserTakeLimitRuleFilter.java (93%) create mode 100644 group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/settlement/TradeSettlementOrderService.java create mode 100644 group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/INotifyTaskDao.java create mode 100644 group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/po/NotifyTask.java create mode 100644 group-buying-sys-types/src/main/java/edu/whut/types/enums/GroupBuyOrderStatusEnumVO.java diff --git a/docs/dev-ops/mysql/sql/0702group_buying_sys.sql b/docs/dev-ops/mysql/sql/0702group_buying_sys.sql index d16361e..fabc86a 100644 --- a/docs/dev-ops/mysql/sql/0702group_buying_sys.sql +++ b/docs/dev-ops/mysql/sql/0702group_buying_sys.sql @@ -183,7 +183,7 @@ CREATE TABLE `group_buy_order_list` ( `channel` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '来源', `original_price` decimal(8, 2) NOT NULL COMMENT '原始价格', `deduction_price` decimal(8, 2) NOT NULL COMMENT '折扣金额', - `status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '状态;0初始锁定、1消费完成', + `status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '状态;0初始锁定、1消费完成、2用户退单', `out_trade_no` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci 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 '更新时间', diff --git a/group-buying-sys-app/src/main/resources/mybatis/mapper/group_buy_order_list_mapper.xml b/group-buying-sys-app/src/main/resources/mybatis/mapper/group_buy_order_list_mapper.xml index bcf63b8..666a93f 100644 --- a/group-buying-sys-app/src/main/resources/mybatis/mapper/group_buy_order_list_mapper.xml +++ b/group-buying-sys-app/src/main/resources/mybatis/mapper/group_buy_order_list_mapper.xml @@ -47,4 +47,13 @@ where user_id = #{userId} and activity_id = #{activityId} + + update group_buy_order_list + set status = 1, update_time = now() + where out_trade_no = #{outTradeNo} and user_id = #{userId} + + + diff --git a/group-buying-sys-app/src/main/resources/mybatis/mapper/group_buy_order_mapper.xml b/group-buying-sys-app/src/main/resources/mybatis/mapper/group_buy_order_mapper.xml index f9ea1a7..b36e658 100644 --- a/group-buying-sys-app/src/main/resources/mybatis/mapper/group_buy_order_mapper.xml +++ b/group-buying-sys-app/src/main/resources/mybatis/mapper/group_buy_order_mapper.xml @@ -37,15 +37,34 @@ ]]> + + + + update group_buy_order set lock_count = lock_count - 1, update_time= now() where team_id = #{teamId} and lock_count > 0 + + update group_buy_order + set status = 1, update_time= now() + where team_id = #{teamId} and status = 0 + + + + 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 new file mode 100644 index 0000000..b843459 --- /dev/null +++ b/group-buying-sys-app/src/main/resources/mybatis/mapper/notify_task_mapper.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + insert into notify_task(activity_id, team_id, notify_url, notify_count, notify_status, parameter_json, + create_time, update_time) + values(#{activityId}, #{teamId}, #{notifyUrl}, #{notifyCount}, #{notifyStatus}, #{parameterJson}, now(),now()) + + + diff --git a/group-buying-sys-app/src/test/java/edu/whut/test/domain/trade/ITradeOrderServiceTest.java b/group-buying-sys-app/src/test/java/edu/whut/test/domain/trade/ITradeLockOrderServiceTest.java similarity index 95% rename from group-buying-sys-app/src/test/java/edu/whut/test/domain/trade/ITradeOrderServiceTest.java rename to group-buying-sys-app/src/test/java/edu/whut/test/domain/trade/ITradeLockOrderServiceTest.java index 4074927..7243058 100644 --- a/group-buying-sys-app/src/test/java/edu/whut/test/domain/trade/ITradeOrderServiceTest.java +++ b/group-buying-sys-app/src/test/java/edu/whut/test/domain/trade/ITradeLockOrderServiceTest.java @@ -8,7 +8,7 @@ import edu.whut.domain.trade.model.entity.MarketPayOrderEntity; import edu.whut.domain.trade.model.entity.PayActivityEntity; import edu.whut.domain.trade.model.entity.PayDiscountEntity; import edu.whut.domain.trade.model.entity.UserEntity; -import edu.whut.domain.trade.service.ITradeOrderService; +import edu.whut.domain.trade.service.ITradeLockOrderService; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.junit.runner.RunWith; @@ -23,13 +23,13 @@ import javax.annotation.Resource; @Slf4j @RunWith(SpringRunner.class) @SpringBootTest -public class ITradeOrderServiceTest { +public class ITradeLockOrderServiceTest { @Resource private IIndexGroupBuyMarketService indexGroupBuyMarketService; @Resource - private ITradeOrderService tradeOrderService; + private ITradeLockOrderService tradeOrderService; @Test public void test_lockMarketPayOrder() throws Exception { diff --git a/group-buying-sys-app/src/test/java/edu/whut/test/domain/trade/TradeSettlementOrderServiceTest.java b/group-buying-sys-app/src/test/java/edu/whut/test/domain/trade/TradeSettlementOrderServiceTest.java new file mode 100644 index 0000000..5601e9a --- /dev/null +++ b/group-buying-sys-app/src/test/java/edu/whut/test/domain/trade/TradeSettlementOrderServiceTest.java @@ -0,0 +1,38 @@ +package edu.whut.test.domain.trade; + +import com.alibaba.fastjson2.JSON; +import edu.whut.domain.trade.model.entity.TradePaySettlementEntity; +import edu.whut.domain.trade.model.entity.TradePaySuccessEntity; +import edu.whut.domain.trade.service.ITradeSettlementOrderService; +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; + +/** + * 拼团交易结算服务测试 + */ +@Slf4j +@RunWith(SpringRunner.class) +@SpringBootTest +public class TradeSettlementOrderServiceTest { + + @Resource + private ITradeSettlementOrderService tradeSettlementOrderService; + + @Test + public void test_settlementMarketPayOrder() { + TradePaySuccessEntity tradePaySuccessEntity = new TradePaySuccessEntity(); + tradePaySuccessEntity.setSource("s01"); + tradePaySuccessEntity.setChannel("c01"); + tradePaySuccessEntity.setUserId("zy03"); + tradePaySuccessEntity.setOutTradeNo("192426946598"); + TradePaySettlementEntity tradePaySettlementEntity = tradeSettlementOrderService.settlementMarketPayOrder(tradePaySuccessEntity); + log.info("请求参数:{}", JSON.toJSONString(tradePaySuccessEntity)); + log.info("测试结果:{}", JSON.toJSONString(tradePaySettlementEntity)); + } + +} diff --git a/group-buying-sys-app/src/test/java/edu/whut/test/trigger/MarketTradeControllerTest.java b/group-buying-sys-app/src/test/java/edu/whut/test/trigger/MarketTradeControllerTest.java index a19dd7d..8053931 100644 --- a/group-buying-sys-app/src/test/java/edu/whut/test/trigger/MarketTradeControllerTest.java +++ b/group-buying-sys-app/src/test/java/edu/whut/test/trigger/MarketTradeControllerTest.java @@ -28,7 +28,7 @@ public class MarketTradeControllerTest { @Test public void test_lockMarketPayOrder() { LockMarketPayOrderRequestDTO lockMarketPayOrderRequestDTO = new LockMarketPayOrderRequestDTO(); - lockMarketPayOrderRequestDTO.setUserId("smile01"); + lockMarketPayOrderRequestDTO.setUserId("zy01"); lockMarketPayOrderRequestDTO.setTeamId(null); lockMarketPayOrderRequestDTO.setActivityId(100123L); lockMarketPayOrderRequestDTO.setGoodsId("9890001"); @@ -44,8 +44,8 @@ public class MarketTradeControllerTest { @Test public void test_lockMarketPayOrder_teamId_not_null() { LockMarketPayOrderRequestDTO lockMarketPayOrderRequestDTO = new LockMarketPayOrderRequestDTO(); - lockMarketPayOrderRequestDTO.setUserId("smile04"); - lockMarketPayOrderRequestDTO.setTeamId("80437493"); + lockMarketPayOrderRequestDTO.setUserId("zy03"); + lockMarketPayOrderRequestDTO.setTeamId("26432069"); lockMarketPayOrderRequestDTO.setActivityId(100123L); lockMarketPayOrderRequestDTO.setGoodsId("9890001"); lockMarketPayOrderRequestDTO.setSource("s01"); diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/tag/service/TagService.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/tag/service/TagService.java index 611b5c5..5e23dd4 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/tag/service/TagService.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/tag/service/TagService.java @@ -40,6 +40,8 @@ public class TagService implements ITagService { add("smile01"); add("smile02"); add("smile03"); + add("smile04"); + add("smile05"); }}; // 4. 把用户写入标签明细表 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 364ca51..cc87e36 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 @@ -1,7 +1,9 @@ package edu.whut.domain.trade.adapter.repository; import edu.whut.domain.trade.model.aggregate.GroupBuyOrderAggregate; +import edu.whut.domain.trade.model.aggregate.GroupBuyTeamSettlementAggregate; import edu.whut.domain.trade.model.entity.GroupBuyActivityEntity; +import edu.whut.domain.trade.model.entity.GroupBuyTeamEntity; import edu.whut.domain.trade.model.entity.MarketPayOrderEntity; import edu.whut.domain.trade.model.valobj.GroupBuyProgressVO; @@ -20,4 +22,9 @@ public interface ITradeRepository { Integer queryOrderCountByActivityId(Long activityId, String userId); + GroupBuyTeamEntity queryGroupBuyTeamByTeamId(String teamId); + + void settlementMarketPayOrder(GroupBuyTeamSettlementAggregate groupBuyTeamSettlementAggregate); + + } diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/aggregate/GroupBuyTeamSettlementAggregate.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/aggregate/GroupBuyTeamSettlementAggregate.java new file mode 100644 index 0000000..4d2442f --- /dev/null +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/aggregate/GroupBuyTeamSettlementAggregate.java @@ -0,0 +1,26 @@ +package edu.whut.domain.trade.model.aggregate; +import edu.whut.domain.trade.model.entity.GroupBuyTeamEntity; +import edu.whut.domain.trade.model.entity.TradePaySuccessEntity; +import edu.whut.domain.trade.model.entity.UserEntity; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 拼团组队结算聚合 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class GroupBuyTeamSettlementAggregate { + + /** 用户实体对象 */ + private UserEntity userEntity; + /** 拼团组队实体对象 */ + private GroupBuyTeamEntity groupBuyTeamEntity; + /** 交易支付订单实体对象 */ + private TradePaySuccessEntity tradePaySuccessEntity; + +} diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/GroupBuyTeamEntity.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/GroupBuyTeamEntity.java new file mode 100644 index 0000000..74bd01c --- /dev/null +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/GroupBuyTeamEntity.java @@ -0,0 +1,30 @@ +package edu.whut.domain.trade.model.entity; +import edu.whut.types.enums.GroupBuyOrderStatusEnumVO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 拼团组队实体对象 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class GroupBuyTeamEntity { + + /** 拼单组队ID */ + private String teamId; + /** 活动ID */ + private Long activityId; + /** 目标数量 */ + private Integer targetCount; + /** 完成数量 */ + private Integer completeCount; + /** 锁单数量 */ + private Integer lockCount; + /** 状态(0-拼单中、1-完成、2-失败) */ + private GroupBuyOrderStatusEnumVO status; + +} diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/MarketPayOrderEntity.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/MarketPayOrderEntity.java index b526777..e87cc11 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/MarketPayOrderEntity.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/MarketPayOrderEntity.java @@ -16,6 +16,8 @@ import java.math.BigDecimal; @NoArgsConstructor public class MarketPayOrderEntity { + /** 拼单组队ID */ + private String teamId; /** 预购订单ID */ private String orderId; /** 折扣金额 */ diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/TradePaySettlementEntity.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/TradePaySettlementEntity.java new file mode 100644 index 0000000..1ee2599 --- /dev/null +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/TradePaySettlementEntity.java @@ -0,0 +1,30 @@ +package edu.whut.domain.trade.model.entity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 交易结算订单实体 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class TradePaySettlementEntity { + + /** 渠道 */ + private String source; + /** 来源 */ + private String channel; + /** 用户ID */ + private String userId; + /** 拼单组队ID */ + private String teamId; + /** 活动ID */ + private Long activityId; + /** 外部交易单号 */ + private String outTradeNo; + +} diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/TradePaySuccessEntity.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/TradePaySuccessEntity.java new file mode 100644 index 0000000..5a0f370 --- /dev/null +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/TradePaySuccessEntity.java @@ -0,0 +1,26 @@ +package edu.whut.domain.trade.model.entity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 交易支付订单实体对象 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class TradePaySuccessEntity { + + /** 渠道 */ + private String source; + /** 来源 */ + private String channel; + /** 用户ID */ + private String userId; + /** 外部交易单号 */ + private String outTradeNo; + +} diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/ITradeOrderService.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/ITradeLockOrderService.java similarity index 96% rename from group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/ITradeOrderService.java rename to group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/ITradeLockOrderService.java index 4fb71df..ffd9b33 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/ITradeOrderService.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/ITradeLockOrderService.java @@ -9,7 +9,7 @@ import edu.whut.domain.trade.model.valobj.GroupBuyProgressVO; /** * 交易订单服务接口 */ -public interface ITradeOrderService { +public interface ITradeLockOrderService { /** * 查询,未被支付消费完成的营销优惠订单 diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/ITradeSettlementOrderService.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/ITradeSettlementOrderService.java new file mode 100644 index 0000000..451ce48 --- /dev/null +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/ITradeSettlementOrderService.java @@ -0,0 +1,18 @@ +package edu.whut.domain.trade.service; + +import edu.whut.domain.trade.model.entity.TradePaySettlementEntity; +import edu.whut.domain.trade.model.entity.TradePaySuccessEntity; + +/** + * 拼团交易结算服务接口 + */ +public interface ITradeSettlementOrderService { + + /** + * 营销结算 + * @param tradePaySuccessEntity 交易支付订单实体对象 + * @return 交易结算订单实体 + */ + TradePaySettlementEntity settlementMarketPayOrder(TradePaySuccessEntity tradePaySuccessEntity); + +} diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/TradeOrderService.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/lock/TradeLockLockOrderService.java similarity index 90% rename from group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/TradeOrderService.java rename to group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/lock/TradeLockLockOrderService.java index b25dc39..9ee4246 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/TradeOrderService.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/lock/TradeLockLockOrderService.java @@ -1,10 +1,11 @@ -package edu.whut.domain.trade.service; +package edu.whut.domain.trade.service.lock; import edu.whut.domain.trade.adapter.repository.ITradeRepository; import edu.whut.domain.trade.model.aggregate.GroupBuyOrderAggregate; import edu.whut.domain.trade.model.entity.*; import edu.whut.domain.trade.model.valobj.GroupBuyProgressVO; -import edu.whut.domain.trade.service.factory.TradeRuleFilterFactory; +import edu.whut.domain.trade.service.ITradeLockOrderService; +import edu.whut.domain.trade.service.lock.factory.TradeRuleFilterFactory; import edu.whut.types.design.framework.link.model2.chain.BusinessLinkedList; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -12,12 +13,12 @@ import org.springframework.stereotype.Service; /** - * 交易订单服务 + * 交易锁单服务,但未支付 */ @Slf4j @Service @RequiredArgsConstructor -public class TradeOrderService implements ITradeOrderService { +public class TradeLockLockOrderService implements ITradeLockOrderService { private final ITradeRepository repository; diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/factory/TradeRuleFilterFactory.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/lock/factory/TradeRuleFilterFactory.java similarity index 89% rename from group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/factory/TradeRuleFilterFactory.java rename to group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/lock/factory/TradeRuleFilterFactory.java index 7119a07..8ded231 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/factory/TradeRuleFilterFactory.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/lock/factory/TradeRuleFilterFactory.java @@ -1,9 +1,9 @@ -package edu.whut.domain.trade.service.factory; +package edu.whut.domain.trade.service.lock.factory; import edu.whut.domain.trade.model.entity.GroupBuyActivityEntity; import edu.whut.domain.trade.model.entity.TradeRuleCommandEntity; import edu.whut.domain.trade.model.entity.TradeRuleFilterBackEntity; -import edu.whut.domain.trade.service.filter.ActivityUsabilityRuleFilter; -import edu.whut.domain.trade.service.filter.UserTakeLimitRuleFilter; +import edu.whut.domain.trade.service.lock.filter.ActivityUsabilityRuleFilter; +import edu.whut.domain.trade.service.lock.filter.UserTakeLimitRuleFilter; import edu.whut.types.design.framework.link.model2.LinkArmory; import edu.whut.types.design.framework.link.model2.chain.BusinessLinkedList; import lombok.AllArgsConstructor; diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/filter/ActivityUsabilityRuleFilter.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/lock/filter/ActivityUsabilityRuleFilter.java similarity index 94% rename from group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/filter/ActivityUsabilityRuleFilter.java rename to group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/lock/filter/ActivityUsabilityRuleFilter.java index f8d7ee5..acc2ec2 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/filter/ActivityUsabilityRuleFilter.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/lock/filter/ActivityUsabilityRuleFilter.java @@ -1,9 +1,9 @@ -package edu.whut.domain.trade.service.filter; +package edu.whut.domain.trade.service.lock.filter; import edu.whut.domain.trade.adapter.repository.ITradeRepository; import edu.whut.domain.trade.model.entity.GroupBuyActivityEntity; import edu.whut.domain.trade.model.entity.TradeRuleCommandEntity; import edu.whut.domain.trade.model.entity.TradeRuleFilterBackEntity; -import edu.whut.domain.trade.service.factory.TradeRuleFilterFactory; +import edu.whut.domain.trade.service.lock.factory.TradeRuleFilterFactory; import edu.whut.types.design.framework.link.model2.handler.ILogicHandler; import edu.whut.types.enums.ActivityStatusEnumVO; import edu.whut.types.enums.ResponseCode; @@ -12,7 +12,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import javax.annotation.Resource; import java.util.Date; /** diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/filter/UserTakeLimitRuleFilter.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/lock/filter/UserTakeLimitRuleFilter.java similarity index 93% rename from group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/filter/UserTakeLimitRuleFilter.java rename to group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/lock/filter/UserTakeLimitRuleFilter.java index 423abf2..0cbb3db 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/filter/UserTakeLimitRuleFilter.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/lock/filter/UserTakeLimitRuleFilter.java @@ -1,9 +1,9 @@ -package edu.whut.domain.trade.service.filter; +package edu.whut.domain.trade.service.lock.filter; import edu.whut.domain.trade.adapter.repository.ITradeRepository; import edu.whut.domain.trade.model.entity.GroupBuyActivityEntity; import edu.whut.domain.trade.model.entity.TradeRuleCommandEntity; import edu.whut.domain.trade.model.entity.TradeRuleFilterBackEntity; -import edu.whut.domain.trade.service.factory.TradeRuleFilterFactory; +import edu.whut.domain.trade.service.lock.factory.TradeRuleFilterFactory; import edu.whut.types.design.framework.link.model2.handler.ILogicHandler; import edu.whut.types.enums.ResponseCode; import edu.whut.types.exception.AppException; diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/settlement/TradeSettlementOrderService.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/settlement/TradeSettlementOrderService.java new file mode 100644 index 0000000..f81211c --- /dev/null +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/settlement/TradeSettlementOrderService.java @@ -0,0 +1,60 @@ +package edu.whut.domain.trade.service.settlement; +import edu.whut.domain.trade.adapter.repository.ITradeRepository; +import edu.whut.domain.trade.model.aggregate.GroupBuyTeamSettlementAggregate; +import edu.whut.domain.trade.model.entity.*; +import edu.whut.domain.trade.service.ITradeSettlementOrderService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +/** + * 拼团交易结算服务 + */ +@Slf4j +@Service +public class TradeSettlementOrderService implements ITradeSettlementOrderService { + + @Resource + private ITradeRepository repository; + + /** + * 第三方支付渠道确认用户“支付成功”之后调用该函数,更新拼团订单状态为 已完成,并同步拼团人数。 + * @param tradePaySuccessEntity 交易支付订单实体对象 + * @return + */ + @Override + public TradePaySettlementEntity settlementMarketPayOrder(TradePaySuccessEntity tradePaySuccessEntity) { + log.info("拼团交易-支付订单结算:{} outTradeNo:{}", tradePaySuccessEntity.getUserId(), tradePaySuccessEntity.getOutTradeNo()); + // 1. 查询拼团信息 + MarketPayOrderEntity marketPayOrderEntity = repository.queryMarketPayOrderEntityByOutTradeNo(tradePaySuccessEntity.getUserId(), tradePaySuccessEntity.getOutTradeNo()); + if (null == marketPayOrderEntity) { + log.info("不存在的外部交易单号或用户已退单,不需要做支付订单结算:{} outTradeNo:{}", tradePaySuccessEntity.getUserId(), tradePaySuccessEntity.getOutTradeNo()); + return null; + } + + // 2. 查询组团信息 + GroupBuyTeamEntity groupBuyTeamEntity = repository.queryGroupBuyTeamByTeamId(marketPayOrderEntity.getTeamId()); + + // 3. 构建聚合对象 + GroupBuyTeamSettlementAggregate groupBuyTeamSettlementAggregate = GroupBuyTeamSettlementAggregate.builder() + .userEntity(UserEntity.builder().userId(tradePaySuccessEntity.getUserId()).build()) + .groupBuyTeamEntity(groupBuyTeamEntity) + .tradePaySuccessEntity(tradePaySuccessEntity) + .build(); + + // 4. 更新数据库,拼团交易结算 + repository.settlementMarketPayOrder(groupBuyTeamSettlementAggregate); + + // 5. 返回结算信息 - 公司中开发这样的流程时候,会根据外部需要进行值的设置 + return TradePaySettlementEntity.builder() + .source(tradePaySuccessEntity.getSource()) + .channel(tradePaySuccessEntity.getChannel()) + .userId(tradePaySuccessEntity.getUserId()) + .teamId(marketPayOrderEntity.getTeamId()) + .activityId(groupBuyTeamEntity.getActivityId()) + .outTradeNo(tradePaySuccessEntity.getOutTradeNo()) + .build(); + } + +} 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 d99692f..bd9e3d6 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 @@ -1,18 +1,23 @@ package edu.whut.infrastructure.adapter.repository; +import com.alibaba.fastjson2.JSON; import edu.whut.domain.trade.adapter.repository.ITradeRepository; import edu.whut.domain.trade.model.aggregate.GroupBuyOrderAggregate; +import edu.whut.domain.trade.model.aggregate.GroupBuyTeamSettlementAggregate; import edu.whut.domain.trade.model.entity.*; import edu.whut.domain.trade.model.valobj.GroupBuyProgressVO; import edu.whut.domain.trade.model.valobj.TradeOrderStatusEnumVO; import edu.whut.infrastructure.dao.IGroupBuyActivityDao; import edu.whut.infrastructure.dao.IGroupBuyOrderDao; import edu.whut.infrastructure.dao.IGroupBuyOrderListDao; +import edu.whut.infrastructure.dao.INotifyTaskDao; import edu.whut.infrastructure.dao.po.GroupBuyActivity; import edu.whut.infrastructure.dao.po.GroupBuyOrder; import edu.whut.infrastructure.dao.po.GroupBuyOrderList; +import edu.whut.infrastructure.dao.po.NotifyTask; import edu.whut.types.common.Constants; import edu.whut.types.enums.ActivityStatusEnumVO; +import edu.whut.types.enums.GroupBuyOrderStatusEnumVO; import edu.whut.types.enums.ResponseCode; import edu.whut.types.exception.AppException; import lombok.RequiredArgsConstructor; @@ -23,6 +28,9 @@ import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; +import java.util.HashMap; +import java.util.List; + /** * 仓储实现:负责把领域对象 <-> 数据库 PO 的转换与持久化; @@ -39,6 +47,8 @@ public class TradeRepository implements ITradeRepository { private final IGroupBuyActivityDao groupBuyActivityDao; + private final INotifyTaskDao notifyTaskDao; + /** * 根据外部交易号 & 用户id 查询未支付的锁单记录(用于幂等) */ @@ -54,8 +64,9 @@ public class TradeRepository implements ITradeRepository { return null; } - // 只返回上层真正关心的属性 + // // 组装领域对象返回,只返回上层真正关心的属性 return MarketPayOrderEntity.builder() + .teamId(po.getTeamId()) .orderId(po.getOrderId()) .deductionPrice(po.getDeductionPrice()) .tradeOrderStatusEnumVO(TradeOrderStatusEnumVO.valueOf(po.getStatus())) @@ -113,6 +124,7 @@ public class TradeRepository implements ITradeRepository { /* ---------- 2. 写入 group_buy_order_list(团单明细表) ---------- */ String orderId = RandomStringUtils.randomNumeric(12); // 订单号 + //构建拼团明细单 GroupBuyOrderList orderListPo = GroupBuyOrderList.builder() .userId(user.getUserId()) .teamId(teamId) @@ -162,6 +174,9 @@ public class TradeRepository implements ITradeRepository { .build(); } + /** + * 根据 activityId 查询拼团活动实体。 + */ @Override public GroupBuyActivityEntity queryGroupBuyActivityEntityByActivityId(Long activityId) { GroupBuyActivity groupBuyActivity = groupBuyActivityDao.queryGroupBuyActivityByActivityId(activityId); @@ -181,6 +196,9 @@ public class TradeRepository implements ITradeRepository { .build(); } + /** + * 查询用户在某活动中已下单次数(用于限购校验)。 + */ @Override public Integer queryOrderCountByActivityId(Long activityId, String userId) { GroupBuyOrderList groupBuyOrderListReq = new GroupBuyOrderList(); @@ -188,4 +206,80 @@ public class TradeRepository implements ITradeRepository { groupBuyOrderListReq.setUserId(userId); return groupBuyOrderListDao.queryOrderCountByActivityId(groupBuyOrderListReq); } + + /** + * 查询团队订单(主表)信息。 + */ + @Override + public GroupBuyTeamEntity queryGroupBuyTeamByTeamId(String teamId) { + GroupBuyOrder groupBuyOrder = groupBuyOrderDao.queryGroupBuyTeamByTeamId(teamId); + return GroupBuyTeamEntity.builder() + .teamId(groupBuyOrder.getTeamId()) + .activityId(groupBuyOrder.getActivityId()) + .targetCount(groupBuyOrder.getTargetCount()) + .completeCount(groupBuyOrder.getCompleteCount()) + .lockCount(groupBuyOrder.getLockCount()) + .status(GroupBuyOrderStatusEnumVO.valueOf(groupBuyOrder.getStatus())) + .build(); + } + + + /** + * 拼团支付成功后的结算逻辑 + * 步骤: + * 更新明细表状态 → COMPLETE + * 更新主表 complete_count + 1 + * 当达到 targetCount 时,更新主表状态 → COMPLETE 并写入回调任务 + * 整体包裹在 500ms 事务内,任何一步失败都会回滚。 + */ + @Transactional(timeout = 500) + @Override + public void settlementMarketPayOrder(GroupBuyTeamSettlementAggregate agg) { + + // ========= 1. 聚合拆分 ========= + UserEntity user = agg.getUserEntity(); + GroupBuyTeamEntity team = agg.getGroupBuyTeamEntity(); + TradePaySuccessEntity payOK = agg.getTradePaySuccessEntity(); + + // ========= 2. 更新拼团订单明细状态 ========= + GroupBuyOrderList req = new GroupBuyOrderList(); + req.setUserId(user.getUserId()); + req.setOutTradeNo(payOK.getOutTradeNo()); + //更新订单状态到已完成 + int rows = groupBuyOrderListDao.updateOrderStatus2COMPLETE(req); + if (rows != 1) { + throw new AppException(ResponseCode.UPDATE_ZERO); + } + + // ========= 3. 更新拼团已完成人数 ========= + int addCnt = groupBuyOrderDao.updateAddCompleteCount(team.getTeamId()); + if (addCnt != 1) { + throw new AppException(ResponseCode.UPDATE_ZERO); + } + + // ========= 4. 达标后收尾(状态改为 COMPLETE & 写入回调任务) ========= + if (team.getTargetCount() - team.getCompleteCount() == 1) { // 刚好凑齐 + int updStat = groupBuyOrderDao.updateOrderStatus2COMPLETE(team.getTeamId()); + if (updStat != 1) { + throw new AppException(ResponseCode.UPDATE_ZERO); + } + + // 查询已完成外部交易号列表,用于业务通知 + List outTradeNoList = groupBuyOrderListDao.queryGroupBuyCompleteOrderOutTradeNoListByTeamId(team.getTeamId()); + + // 构造并写入通知任务(异步回调) + NotifyTask task = new NotifyTask(); + task.setActivityId(team.getActivityId()); + task.setTeamId(team.getTeamId()); + task.setNotifyUrl("暂无"); // TODO:待配置回调地址 + task.setNotifyCount(0); + task.setNotifyStatus(0); + task.setParameterJson(JSON.toJSONString(new HashMap() {{ + put("teamId", team.getTeamId()); + put("outTradeNoList", outTradeNoList); + }})); + + notifyTaskDao.insert(task); + } + } } diff --git a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/IGroupBuyOrderDao.java b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/IGroupBuyOrderDao.java index ca39948..c664fb1 100644 --- a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/IGroupBuyOrderDao.java +++ b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/IGroupBuyOrderDao.java @@ -31,4 +31,10 @@ public interface IGroupBuyOrderDao { */ GroupBuyOrder queryGroupBuyProgress(String teamId); + GroupBuyOrder queryGroupBuyTeamByTeamId(String teamId); + + int updateAddCompleteCount(String teamId); + + int updateOrderStatus2COMPLETE(String teamId); + } diff --git a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/IGroupBuyOrderListDao.java b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/IGroupBuyOrderListDao.java index 163b178..9d0b246 100644 --- a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/IGroupBuyOrderListDao.java +++ b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/IGroupBuyOrderListDao.java @@ -2,6 +2,8 @@ package edu.whut.infrastructure.dao; import edu.whut.infrastructure.dao.po.GroupBuyOrderList; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + /** * 用户拼单明细 */ @@ -19,4 +21,9 @@ public interface IGroupBuyOrderListDao { Integer queryOrderCountByActivityId(GroupBuyOrderList groupBuyOrderListReq); + int updateOrderStatus2COMPLETE(GroupBuyOrderList groupBuyOrderListReq); + + List queryGroupBuyCompleteOrderOutTradeNoListByTeamId(String teamId); + + } 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 new file mode 100644 index 0000000..9e69322 --- /dev/null +++ b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/INotifyTaskDao.java @@ -0,0 +1,13 @@ +package edu.whut.infrastructure.dao; +import edu.whut.infrastructure.dao.po.NotifyTask; +import org.apache.ibatis.annotations.Mapper; + +/** + * 回调任务 + */ +@Mapper +public interface INotifyTaskDao { + + void insert(NotifyTask notifyTask); + +} diff --git a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/po/NotifyTask.java b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/po/NotifyTask.java new file mode 100644 index 0000000..8568d3e --- /dev/null +++ b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/po/NotifyTask.java @@ -0,0 +1,37 @@ +package edu.whut.infrastructure.dao.po; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * 通知回调任务 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class NotifyTask { + + /** 自增ID */ + private Long id; + /** 活动ID */ + private Long activityId; + /** 拼单组队ID */ + private String teamId; + /** 回调接口 */ + private String notifyUrl; + /** 回调次数 */ + private Integer notifyCount; + /** 回调状态【0初始、1完成、2重试、3失败】 */ + private Integer notifyStatus; + /** 参数对象 */ + private String parameterJson; + /** 创建时间 */ + private Date createTime; + /** 更新时间 */ + private Date updateTime; + +} diff --git a/group-buying-sys-trigger/src/main/java/edu/whut/trigger/http/MarketTradeController.java b/group-buying-sys-trigger/src/main/java/edu/whut/trigger/http/MarketTradeController.java index dc5b1d6..cf6988b 100644 --- a/group-buying-sys-trigger/src/main/java/edu/whut/trigger/http/MarketTradeController.java +++ b/group-buying-sys-trigger/src/main/java/edu/whut/trigger/http/MarketTradeController.java @@ -14,7 +14,7 @@ import edu.whut.domain.trade.model.entity.PayActivityEntity; import edu.whut.domain.trade.model.entity.PayDiscountEntity; import edu.whut.domain.trade.model.entity.UserEntity; import edu.whut.domain.trade.model.valobj.GroupBuyProgressVO; -import edu.whut.domain.trade.service.ITradeOrderService; +import edu.whut.domain.trade.service.ITradeLockOrderService; import edu.whut.types.enums.ResponseCode; import edu.whut.types.exception.AppException; import lombok.RequiredArgsConstructor; @@ -47,7 +47,7 @@ public class MarketTradeController implements IMarketTradeService { private final IIndexGroupBuyMarketService indexGroupBuyMarketService; - private final ITradeOrderService tradeOrderService; + private final ITradeLockOrderService tradeOrderService; /** * 锁定营销预支付订单(拼团 / 普通优惠) diff --git a/group-buying-sys-types/src/main/java/edu/whut/types/enums/GroupBuyOrderStatusEnumVO.java b/group-buying-sys-types/src/main/java/edu/whut/types/enums/GroupBuyOrderStatusEnumVO.java new file mode 100644 index 0000000..9f87e7e --- /dev/null +++ b/group-buying-sys-types/src/main/java/edu/whut/types/enums/GroupBuyOrderStatusEnumVO.java @@ -0,0 +1,35 @@ +package edu.whut.types.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * 拼团订单枚举 + */ +@Getter +@AllArgsConstructor +@NoArgsConstructor +public enum GroupBuyOrderStatusEnumVO { + + PROGRESS(0, "拼单中"), + COMPLETE(1, "完成"), + FAIL(2, "失败"), + ; + + private Integer code; + private String info; + + public static GroupBuyOrderStatusEnumVO valueOf(Integer code) { + switch (code) { + case 0: + return PROGRESS; + case 1: + return COMPLETE; + case 2: + return FAIL; + } + throw new RuntimeException("err code not exist!"); + } + +} diff --git a/group-buying-sys-types/src/main/java/edu/whut/types/enums/ResponseCode.java b/group-buying-sys-types/src/main/java/edu/whut/types/enums/ResponseCode.java index 6743f90..eb3662b 100644 --- a/group-buying-sys-types/src/main/java/edu/whut/types/enums/ResponseCode.java +++ b/group-buying-sys-types/src/main/java/edu/whut/types/enums/ResponseCode.java @@ -13,6 +13,8 @@ public enum ResponseCode { UN_ERROR("0001", "未知失败"), ILLEGAL_PARAMETER("0002", "非法参数"), INDEX_EXCEPTION("0003", "唯一索引冲突"), + UPDATE_ZERO("0004", "更新记录为0"), + E0001("E0001", "不存在对应的折扣计算服务"), E0002("E0002", "无拼团营销配置"), E0003("E0003", "拼团活动降级拦截"),