From f8429e9fcdce8be7c68d0d4155953473003438f2 Mon Sep 17 00:00:00 2001 From: zhangsan <646228430@qq.com> Date: Wed, 2 Jul 2025 13:54:13 +0800 Subject: [PATCH] =?UTF-8?q?7.2=20=E8=B4=A3=E4=BB=BB=E9=93=BE=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=20=E5=8A=9F=E8=83=BD=E5=AE=8C=E5=96=84+=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=BC=96=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mysql/sql/0702group_buying_sys.sql | 247 ++++++++++++++++++ .../sql => sql-back}/0630group_buying_sys.sql | 0 .../mapper/group_buy_activity_mapper.xml | 8 + .../mapper/group_buy_order_list_mapper.xml | 10 +- .../domain/trade/ITradeOrderServiceTest.java | 3 +- .../trigger/MarketTradeControllerTest.java | 7 +- .../repository/IActivityRepository.java | 2 +- .../AbstractDiscountCalculateService.java | 9 +- .../whut/domain/tag/service/TagService.java | 3 + .../aggregate/GroupBuyOrderAggregate.java | 2 + .../trade/service/ITradeOrderService.java | 2 +- .../trade/service/TradeOrderService.java | 29 +- .../repository/ActivityRepository.java | 5 +- .../dao/IGroupBuyActivityDao.java | 2 + .../dao/IGroupBuyOrderListDao.java | 2 + .../dao/po/GroupBuyOrderList.java | 2 + .../link/model2/handler/ILogicHandler.java | 11 +- 17 files changed, 321 insertions(+), 23 deletions(-) create mode 100644 docs/dev-ops/mysql/sql/0702group_buying_sys.sql rename docs/dev-ops/{mysql/sql => sql-back}/0630group_buying_sys.sql (100%) diff --git a/docs/dev-ops/mysql/sql/0702group_buying_sys.sql b/docs/dev-ops/mysql/sql/0702group_buying_sys.sql new file mode 100644 index 0000000..d16361e --- /dev/null +++ b/docs/dev-ops/mysql/sql/0702group_buying_sys.sql @@ -0,0 +1,247 @@ +/* + Navicat Premium Data Transfer + + Source Server : group_buy + Source Server Type : MySQL + Source Server Version : 80042 + Source Host : localhost:13306 + Source Schema : group_buying_sys + + Target Server Type : MySQL + Target Server Version : 80042 + File Encoding : 65001 + + Date: 02/07/2025 13:52:59 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for crowd_tags +-- ---------------------------- +DROP TABLE IF EXISTS `crowd_tags`; +CREATE TABLE `crowd_tags` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `tag_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '人群ID', + `tag_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '人群名称', + `tag_desc` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '人群描述', + `statistics` int 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_tag_id`(`tag_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '人群标签' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of crowd_tags +-- ---------------------------- +INSERT INTO `crowd_tags` VALUES (1, 'RQ_KJHKL98UU78H66554GFDV', '潜在消费用户', '潜在消费用户', 28, '2025-06-26 09:12:22', '2025-06-28 11:02:00'); + +-- ---------------------------- +-- Table structure for crowd_tags_detail +-- ---------------------------- +DROP TABLE IF EXISTS `crowd_tags_detail`; +CREATE TABLE `crowd_tags_detail` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `tag_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '人群ID', + `user_id` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户ID', + `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_tag_user`(`tag_id` ASC, `user_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 25 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '人群标签明细' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of crowd_tags_detail +-- ---------------------------- +INSERT INTO `crowd_tags_detail` VALUES (20, 'RQ_KJHKL98UU78H66554GFDV', 'zy123', '2025-06-28 10:53:23', '2025-06-28 10:53:23'); +INSERT INTO `crowd_tags_detail` VALUES (21, 'RQ_KJHKL98UU78H66554GFDV', 'smile', '2025-06-28 10:53:23', '2025-06-28 10:53:23'); + +-- ---------------------------- +-- Table structure for crowd_tags_job +-- ---------------------------- +DROP TABLE IF EXISTS `crowd_tags_job`; +CREATE TABLE `crowd_tags_job` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `tag_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '标签ID', + `batch_id` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '批次ID', + `tag_type` tinyint(1) NOT NULL DEFAULT 1 COMMENT '标签类型(参与量、消费金额)', + `tag_rule` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '标签规则(限定类型 N次)', + `stat_start_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '统计数据,开始时间', + `stat_end_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '统计数据,结束时间', + `status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '状态;0初始、1计划(进入执行阶段)、2重置、3完成', + `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_batch_id`(`batch_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '人群标签任务' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of crowd_tags_job +-- ---------------------------- +INSERT INTO `crowd_tags_job` VALUES (1, 'RQ_KJHKL98UU78H66554GFDV', '10001', 0, '100', '2025-06-26 09:13:31', '2025-06-26 09:13:31', 0, '2025-06-26 09:13:31', '2025-06-26 09:13:31'); + +-- ---------------------------- +-- Table structure for group_buy_activity +-- ---------------------------- +DROP TABLE IF EXISTS `group_buy_activity`; +CREATE TABLE `group_buy_activity` ( + `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增', + `activity_id` bigint NOT NULL COMMENT '活动ID', + `activity_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '活动名称', + `discount_id` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '折扣ID', + `group_type` tinyint(1) NOT NULL DEFAULT 0 COMMENT '拼团方式(0自动成团、1达成目标拼团)', + `take_limit_count` int NOT NULL DEFAULT 1 COMMENT '拼团次数限制', + `target` int NOT NULL DEFAULT 1 COMMENT '拼团目标', + `valid_time` int NOT NULL DEFAULT 15 COMMENT '拼团时长(分钟)', + `status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '活动状态(0创建、1生效、2过期、3废弃)', + `start_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '活动开始时间', + `end_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '活动结束时间', + `tag_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '人群标签规则标识', + `tag_scope` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '人群标签规则范围(多选;1可见限制、2参与限制)', + `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_activity_id`(`activity_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '拼团活动' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of group_buy_activity +-- ---------------------------- +INSERT INTO `group_buy_activity` VALUES (1, 100123, '测试活动', '25120207', 0, 1, 3, 15, 1, '2025-06-19 10:19:40', '2025-07-31 10:19:40', 'RQ_KJHKL98UU78H66554GFDV', '1,2', '2025-06-19 10:19:40', '2025-07-02 13:21:27'); + +-- ---------------------------- +-- Table structure for group_buy_discount +-- ---------------------------- +DROP TABLE IF EXISTS `group_buy_discount`; +CREATE TABLE `group_buy_discount` ( + `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `discount_id` int NOT NULL COMMENT '折扣ID', + `discount_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '折扣标题', + `discount_desc` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '折扣描述', + `discount_type` tinyint(1) NOT NULL DEFAULT 0 COMMENT '折扣类型(0:base、1:tag)', + `market_plan` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'ZJ' COMMENT '营销优惠计划(ZJ:直减、MJ:满减、ZK:折扣、N元购)', + `market_expr` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '营销优惠表达式', + `tag_id` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT 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_discount_id`(`discount_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '折扣配置' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of group_buy_discount +-- ---------------------------- +INSERT INTO `group_buy_discount` VALUES (1, 25120207, '直减优惠20元', '直减优惠20元', 0, 'ZJ', '20', NULL, '2025-06-25 14:02:13', '2025-06-25 14:02:13'); +INSERT INTO `group_buy_discount` VALUES (2, 25120208, '满减优惠100-10元', '满减优惠100-10元', 0, 'MJ', '100,10', NULL, '2025-06-25 14:02:13', '2025-06-25 14:02:13'); +INSERT INTO `group_buy_discount` VALUES (4, 25120209, '折扣优惠8折', '折扣优惠8折', 0, 'ZK', '0.8', NULL, '2025-06-25 14:02:13', '2025-06-25 14:02:13'); +INSERT INTO `group_buy_discount` VALUES (5, 25120210, 'N元购买优惠', 'N元购买优惠', 0, 'N', '1.99', NULL, '2025-06-25 14:02:13', '2025-06-25 14:02:13'); + +-- ---------------------------- +-- Table structure for group_buy_order +-- ---------------------------- +DROP TABLE IF EXISTS `group_buy_order`; +CREATE TABLE `group_buy_order` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `team_id` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '拼单组队ID', + `activity_id` bigint NOT NULL COMMENT '活动ID', + `source` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '渠道', + `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 '折扣金额', + `pay_price` decimal(8, 2) NOT NULL COMMENT '支付价格', + `target_count` int NOT NULL COMMENT '目标数量', + `complete_count` int NOT NULL COMMENT '完成数量', + `lock_count` int NOT NULL COMMENT '锁单数量', + `status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '状态(0-拼单中、1-完成、2-失败)', + `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_team_id`(`team_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '拼团订单表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of group_buy_order +-- ---------------------------- +INSERT INTO `group_buy_order` VALUES (4, '80437493', 100123, 's01', 'c01', 100.00, 20.00, 80.00, 5, 0, 4, 0, '2025-07-02 13:31:35', '2025-07-02 13:48:16'); + +-- ---------------------------- +-- Table structure for group_buy_order_list +-- ---------------------------- +DROP TABLE IF EXISTS `group_buy_order_list`; +CREATE TABLE `group_buy_order_list` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `user_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户ID', + `team_id` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '拼单组队ID', + `order_id` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '订单ID', + `activity_id` bigint NOT NULL COMMENT '活动ID', + `start_time` datetime NOT NULL COMMENT '活动开始时间', + `end_time` datetime NOT NULL COMMENT '活动结束时间', + `goods_id` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品ID', + `source` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '渠道', + `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消费完成', + `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 '更新时间', + `biz_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '业务唯一ID', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `uq_order_id`(`order_id` ASC) USING BTREE, + INDEX `idx_user_id_activity_id`(`user_id` ASC, `activity_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '拼团订单明细表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of group_buy_order_list +-- ---------------------------- +INSERT INTO `group_buy_order_list` VALUES (6, 'smile01', '80437493', '915634883913', 100123, '2025-06-19 10:19:40', '2025-07-31 10:19:40', '9890001', 's01', 'c01', 100.00, 20.00, 0, '093147606342', '2025-07-02 13:31:35', '2025-07-02 13:31:35', '100123_smile01_1'); +INSERT INTO `group_buy_order_list` VALUES (7, 'smile02', '80437493', '337142187685', 100123, '2025-06-19 10:19:40', '2025-07-31 10:19:40', '9890001', 's01', 'c01', 100.00, 20.00, 0, '835118458939', '2025-07-02 13:40:23', '2025-07-02 13:40:23', '100123_smile02_1'); +INSERT INTO `group_buy_order_list` VALUES (8, 'smile03', '80437493', '299471294958', 100123, '2025-06-19 10:19:40', '2025-07-31 10:19:40', '9890001', 's01', 'c01', 100.00, 20.00, 0, '135668811039', '2025-07-02 13:41:31', '2025-07-02 13:41:31', '100123_smile03_1'); +INSERT INTO `group_buy_order_list` VALUES (9, 'smile04', '80437493', '254753792328', 100123, '2025-06-19 10:19:40', '2025-07-31 10:19:40', '9890001', 's01', 'c01', 100.00, 20.00, 0, '088164349390', '2025-07-02 13:47:45', '2025-07-02 13:47:45', '100123_smile04_1'); + +-- ---------------------------- +-- Table structure for sc_sku_activity +-- ---------------------------- +DROP TABLE IF EXISTS `sc_sku_activity`; +CREATE TABLE `sc_sku_activity` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `source` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '渠道', + `channel` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '来源', + `activity_id` bigint NOT NULL COMMENT '活动ID', + `goods_id` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品ID', + `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_sc_goodsid`(`source` ASC, `channel` ASC, `goods_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '渠道商品活动配置关联表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sc_sku_activity +-- ---------------------------- +INSERT INTO `sc_sku_activity` VALUES (1, 's01', 'c01', 100123, '9890001', '2025-06-26 17:15:54', '2025-06-26 17:15:54'); + +-- ---------------------------- +-- Table structure for sku +-- ---------------------------- +DROP TABLE IF EXISTS `sku`; +CREATE TABLE `sku` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `source` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '渠道', + `channel` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '来源', + `goods_id` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品ID', + `goods_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品名称', + `original_price` decimal(10, 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_goods_id`(`goods_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '商品信息' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sku +-- ---------------------------- +INSERT INTO `sku` VALUES (1, 's01', 'c01', '9890001', '《手写MyBatis:渐进式源码实践》', 100.00, '2025-06-22 11:10:06', '2025-06-22 11:10:06'); + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/docs/dev-ops/mysql/sql/0630group_buying_sys.sql b/docs/dev-ops/sql-back/0630group_buying_sys.sql similarity index 100% rename from docs/dev-ops/mysql/sql/0630group_buying_sys.sql rename to docs/dev-ops/sql-back/0630group_buying_sys.sql diff --git a/group-buying-sys-app/src/main/resources/mybatis/mapper/group_buy_activity_mapper.xml b/group-buying-sys-app/src/main/resources/mybatis/mapper/group_buy_activity_mapper.xml index d55e266..ed12276 100644 --- a/group-buying-sys-app/src/main/resources/mybatis/mapper/group_buy_activity_mapper.xml +++ b/group-buying-sys-app/src/main/resources/mybatis/mapper/group_buy_activity_mapper.xml @@ -42,4 +42,12 @@ where activity_id = #{activityId} and status = 1 + + 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 0c43d01..bcf63b8 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 @@ -17,6 +17,7 @@ + @@ -25,12 +26,12 @@ insert into group_buy_order_list( user_id, team_id, order_id, activity_id, start_time, end_time, goods_id, source, channel, original_price, - deduction_price, status, out_trade_no, create_time, update_time + deduction_price, status, out_trade_no, biz_id, create_time, update_time ) values( #{userId}, #{teamId}, #{orderId}, #{activityId}, #{startTime}, #{endTime}, #{goodsId}, #{source}, #{channel}, #{originalPrice}, - #{deductionPrice}, #{status}, #{outTradeNo}, now(), now() + #{deductionPrice}, #{status}, #{outTradeNo}, #{bizId}, now(), now() ) @@ -41,4 +42,9 @@ where out_trade_no = #{outTradeNo} and user_id = #{userId} and status = 0 + + 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/ITradeOrderServiceTest.java index 6824263..4074927 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/ITradeOrderServiceTest.java @@ -35,7 +35,7 @@ public class ITradeOrderServiceTest { public void test_lockMarketPayOrder() throws Exception { // 入参信息 Long activityId = 100123L; - String userId = "xiaofuge"; + String userId = "smile"; String goodsId = "9890001"; String source = "s01"; String channel = "c01"; @@ -50,6 +50,7 @@ public class ITradeOrderServiceTest { .activityId(activityId) .build()); + //获取活动配置信息 GroupBuyActivityDiscountVO groupBuyActivityDiscountVO = trialBalanceEntity.getGroupBuyActivityDiscountVO(); // 查询 outTradeNo 是否已经存在交易记录 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 d177cf9..a19dd7d 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 @@ -24,10 +24,11 @@ public class MarketTradeControllerTest { @Resource private IMarketTradeService marketTradeService; + @Test public void test_lockMarketPayOrder() { LockMarketPayOrderRequestDTO lockMarketPayOrderRequestDTO = new LockMarketPayOrderRequestDTO(); - lockMarketPayOrderRequestDTO.setUserId("smile"); + lockMarketPayOrderRequestDTO.setUserId("smile01"); lockMarketPayOrderRequestDTO.setTeamId(null); lockMarketPayOrderRequestDTO.setActivityId(100123L); lockMarketPayOrderRequestDTO.setGoodsId("9890001"); @@ -43,8 +44,8 @@ public class MarketTradeControllerTest { @Test public void test_lockMarketPayOrder_teamId_not_null() { LockMarketPayOrderRequestDTO lockMarketPayOrderRequestDTO = new LockMarketPayOrderRequestDTO(); - lockMarketPayOrderRequestDTO.setUserId("smile"); - lockMarketPayOrderRequestDTO.setTeamId("41763306"); + lockMarketPayOrderRequestDTO.setUserId("smile04"); + lockMarketPayOrderRequestDTO.setTeamId("80437493"); lockMarketPayOrderRequestDTO.setActivityId(100123L); lockMarketPayOrderRequestDTO.setGoodsId("9890001"); lockMarketPayOrderRequestDTO.setSource("s01"); diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/adapter/repository/IActivityRepository.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/adapter/repository/IActivityRepository.java index afa0663..f23d58f 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/adapter/repository/IActivityRepository.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/adapter/repository/IActivityRepository.java @@ -14,7 +14,7 @@ public interface IActivityRepository { SCSkuActivityVO querySCSkuActivityBySCGoodsId(String source, String channel, String goodsId); - boolean isTagCrowdRange(String tagId, String userId); + boolean isTagCrowdRange(String userId, String tagId); boolean downgradeSwitch(); diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/discount/AbstractDiscountCalculateService.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/discount/AbstractDiscountCalculateService.java index f25bf41..a2dccb8 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/discount/AbstractDiscountCalculateService.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/discount/AbstractDiscountCalculateService.java @@ -6,16 +6,17 @@ import edu.whut.domain.activity.model.valobj.GroupBuyActivityDiscountVO; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import javax.annotation.Resource; import java.math.BigDecimal; /** * 折扣计算服务抽象类 */ -@RequiredArgsConstructor @Slf4j public abstract class AbstractDiscountCalculateService implements IDiscountCalculateService { - final protected IActivityRepository repository; + @Resource + protected IActivityRepository repository; @Override public BigDecimal calculate(String userId, BigDecimal originalPrice, GroupBuyActivityDiscountVO.GroupBuyDiscount groupBuyDiscount) { // 1. 人群标签过滤, 只有当 discountType = TAG 时才检查用户是否在标签范围内 @@ -30,9 +31,9 @@ public abstract class AbstractDiscountCalculateService implements IDiscountCalcu return doCalculate(originalPrice, groupBuyDiscount); } - // 人群过滤 - 限定人群优惠 + // 人群过滤 - 限定优惠人群,return true->属于优惠人群 private boolean filterTagId(String userId, String tagId) { - return repository.isTagCrowdRange(tagId, userId); + return repository.isTagCrowdRange(userId, tagId); } //留给子类实现的抽象方法,真正去算“直减多少 / 满减多少 / N 元购” protected abstract BigDecimal doCalculate(BigDecimal originalPrice, GroupBuyActivityDiscountVO.GroupBuyDiscount groupBuyDiscount); 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 9f3745d..611b5c5 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 @@ -37,6 +37,9 @@ public class TagService implements ITagService { List userIdList = new ArrayList() {{ add("zy123"); add("smile"); + add("smile01"); + add("smile02"); + add("smile03"); }}; // 4. 把用户写入标签明细表 diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/aggregate/GroupBuyOrderAggregate.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/aggregate/GroupBuyOrderAggregate.java index 6147177..bdce215 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/aggregate/GroupBuyOrderAggregate.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/aggregate/GroupBuyOrderAggregate.java @@ -22,5 +22,7 @@ public class GroupBuyOrderAggregate { private PayActivityEntity payActivityEntity; /** 支付优惠实体对象 */ private PayDiscountEntity payDiscountEntity; + /** 已参与拼团量 */ + private Integer userTakeOrderCount; } 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/ITradeOrderService.java index 90f905e..4fb71df 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/ITradeOrderService.java @@ -36,6 +36,6 @@ public interface ITradeOrderService { * @param payDiscountEntity 拼团,支付优惠实体对象 * @return 拼团,预购订单营销实体对象 */ - MarketPayOrderEntity lockMarketPayOrder(UserEntity userEntity, PayActivityEntity payActivityEntity, PayDiscountEntity payDiscountEntity); + MarketPayOrderEntity lockMarketPayOrder(UserEntity userEntity, PayActivityEntity payActivityEntity, PayDiscountEntity payDiscountEntity)throws Exception; } 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/TradeOrderService.java index dfe5a98..b25dc39 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/TradeOrderService.java @@ -2,25 +2,28 @@ package edu.whut.domain.trade.service; import edu.whut.domain.trade.adapter.repository.ITradeRepository; import edu.whut.domain.trade.model.aggregate.GroupBuyOrderAggregate; -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.model.entity.*; import edu.whut.domain.trade.model.valobj.GroupBuyProgressVO; +import edu.whut.domain.trade.service.factory.TradeRuleFilterFactory; +import edu.whut.types.design.framework.link.model2.chain.BusinessLinkedList; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import javax.annotation.Resource; /** * 交易订单服务 */ @Slf4j @Service +@RequiredArgsConstructor public class TradeOrderService implements ITradeOrderService { - @Resource - private ITradeRepository repository; + private final ITradeRepository repository; + + //注入责任链,tradeRuleFilter为自定义bean名 + private final BusinessLinkedList tradeRuleFilter; + @Override public MarketPayOrderEntity queryNoPayMarketPayOrderByOutTradeNo(String userId, String outTradeNo) { @@ -35,14 +38,24 @@ public class TradeOrderService implements ITradeOrderService { } @Override - public MarketPayOrderEntity lockMarketPayOrder(UserEntity userEntity, PayActivityEntity payActivityEntity, PayDiscountEntity payDiscountEntity) { + public MarketPayOrderEntity lockMarketPayOrder(UserEntity userEntity, PayActivityEntity payActivityEntity, PayDiscountEntity payDiscountEntity) throws Exception{ log.info("拼团交易-锁定营销优惠支付订单:{} activityId:{} goodsId:{}", userEntity.getUserId(), payActivityEntity.getActivityId(), payDiscountEntity.getGoodsId()); + // 责任链校验:确保活动仍有效、用户参与次数未到上限。 + TradeRuleFilterBackEntity tradeRuleFilterBackEntity = tradeRuleFilter.apply(TradeRuleCommandEntity.builder() + .activityId(payActivityEntity.getActivityId()) + .userId(userEntity.getUserId()) + .build(), + new TradeRuleFilterFactory.DynamicContext()); + + // 获得该用户在该活动上已参与的拼团量 - 用于构建数据库唯一索引使用,确保用户只能在一个活动上参与固定的次数 + Integer userTakeOrderCount = tradeRuleFilterBackEntity.getUserTakeOrderCount(); // 构建聚合对象 GroupBuyOrderAggregate groupBuyOrderAggregate = GroupBuyOrderAggregate.builder() .userEntity(userEntity) .payActivityEntity(payActivityEntity) .payDiscountEntity(payDiscountEntity) + .userTakeOrderCount(userTakeOrderCount) .build(); // 锁定聚合订单 - 这会用户只是下单还没有支付。后续会有2个流程;支付成功、超时未支付(回退) diff --git a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/ActivityRepository.java b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/ActivityRepository.java index cc3abe2..03b1bad 100644 --- a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/ActivityRepository.java +++ b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/ActivityRepository.java @@ -106,13 +106,14 @@ public class ActivityRepository implements IActivityRepository { } @Override - public boolean isTagCrowdRange(String tagId, String userId) { + public boolean isTagCrowdRange(String userId, String tagId) { //根据标签id获取对应位图 RBitSet bitSet = redisService.getBitSet(tagId); if (!bitSet.isExists()) { + //「如果后台没配置标签,默认所有用户都在优惠范围」。 return true; } - // 判断用户是否存在人群中 + // 判断用户是否在优惠人群中,仅在名单范围内返回true return bitSet.get(redisService.getIndexFromUserId(userId)); } diff --git a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/IGroupBuyActivityDao.java b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/IGroupBuyActivityDao.java index 86ef498..11df2c6 100644 --- a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/IGroupBuyActivityDao.java +++ b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/IGroupBuyActivityDao.java @@ -15,4 +15,6 @@ public interface IGroupBuyActivityDao { GroupBuyActivity queryValidGroupBuyActivityId(Long activityId); + GroupBuyActivity queryGroupBuyActivityByActivityId(Long activityId); + } 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 57ac8af..163b178 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 @@ -17,4 +17,6 @@ public interface IGroupBuyOrderListDao { */ GroupBuyOrderList queryGroupBuyOrderRecordByOutTradeNo(GroupBuyOrderList groupBuyOrderListReq); + Integer queryOrderCountByActivityId(GroupBuyOrderList groupBuyOrderListReq); + } diff --git a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/po/GroupBuyOrderList.java b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/po/GroupBuyOrderList.java index f23f6a0..ddfda2f 100644 --- a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/po/GroupBuyOrderList.java +++ b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/po/GroupBuyOrderList.java @@ -45,6 +45,8 @@ public class GroupBuyOrderList { private Integer status; /** 外部交易单号-确保外部调用唯一幂等 */ private String outTradeNo; + /** 唯一业务ID */ + private String bizId; /** 创建时间 */ private Date createTime; /** 更新时间 */ diff --git a/group-buying-sys-types/src/main/java/edu/whut/types/design/framework/link/model2/handler/ILogicHandler.java b/group-buying-sys-types/src/main/java/edu/whut/types/design/framework/link/model2/handler/ILogicHandler.java index c7da864..4058bf1 100644 --- a/group-buying-sys-types/src/main/java/edu/whut/types/design/framework/link/model2/handler/ILogicHandler.java +++ b/group-buying-sys-types/src/main/java/edu/whut/types/design/framework/link/model2/handler/ILogicHandler.java @@ -1,14 +1,23 @@ package edu.whut.types.design.framework.link.model2.handler; /** - * 逻辑处理器 + * 通用逻辑处理器接口 —— 责任链中的「节点」要实现的核心契约。 + * T:请求参数类型,通常是不可变的命令 / 请求对象。 + * D:动态上下文类型,在链路中传递可写信息。 + * R:处理结果类型,返回非 null 表示链路命中并直接结束。 */ public interface ILogicHandler { + /** + * 默认的 next占位实现,方便节点若不需要向后传递时直接返回 null。 + */ default R next(T requestParameter, D dynamicContext) { return null; } + /** + * 节点的核心处理方法。 + */ R apply(T requestParameter, D dynamicContext) throws Exception; }