7.25 添加策略模板,考虑三种退单情况,先实现未支付退单
This commit is contained in:
parent
645255ecf5
commit
0ffedfa501
277
docs/dev-ops/sql-back/0719group_buying_sys.sql
Normal file
277
docs/dev-ops/sql-back/0719group_buying_sys.sql
Normal file
@ -0,0 +1,277 @@
|
||||
/*
|
||||
Navicat Premium Data Transfer
|
||||
|
||||
Source Server : group_buy_local
|
||||
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: 25/07/2025 13:12:15
|
||||
*/
|
||||
|
||||
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 = 21 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, 60, 1, '2025-06-19 10:19:40', '2025-12-31 10:19:40', 'RQ_KJHKL98UU78H66554GFDV', '1,2', '2025-06-19 10:19:40', '2025-07-25 12:59:18');
|
||||
INSERT INTO `group_buy_activity` VALUES (2, 100124, '测试活动2', '25120207', 0, 1, 1, 60, 1, '2025-07-05 13:39:52', '2025-12-31 13:39:34', 'RQ_KJHKL98UU78H66554GFDV', '1,2', '2025-07-05 13:39:52', '2025-07-25 12:59:23');
|
||||
|
||||
-- ----------------------------
|
||||
-- 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 = 5 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-失败)',
|
||||
`valid_start_time` datetime NOT NULL COMMENT '拼团开始时间',
|
||||
`valid_end_time` datetime NOT NULL COMMENT '拼团结束时间',
|
||||
`notify_type` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'HTTP' COMMENT '回调类型(HTTP、MQ)',
|
||||
`notify_url` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '回调地址(HTTP 回调不可为空)',
|
||||
`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 = 39 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '拼团订单表' ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of group_buy_order
|
||||
-- ----------------------------
|
||||
INSERT INTO `group_buy_order` VALUES (40, '51446037', 100123, 's01', 'c01', 100.00, 20.00, 80.00, 3, 0, 1, 0, '2025-07-25 13:02:13', '2025-07-25 14:02:13', 'HTTP', 'http://127.0.0.1:8091/api/v1/test/group_buy_notify', '2025-07-25 13:02:13', '2025-07-25 13:05:38');
|
||||
|
||||
-- ----------------------------
|
||||
-- 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 '折扣金额',
|
||||
`pay_price` decimal(8, 2) NOT NULL COMMENT '支付金额',
|
||||
`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 '更新时间',
|
||||
`biz_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '业务唯一ID',
|
||||
`out_trade_time` datetime NULL DEFAULT NULL COMMENT '外部交易时间',
|
||||
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 = 37 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 (38, 'smile01', '51446037', '880814041251', 100123, '2025-06-19 10:19:40', '2025-07-31 10:19:40', '9890001', 's01', 'c01', 100.00, 20.00, 80.00, 0, '928126330755', '2025-07-25 13:02:13', '2025-07-25 13:02:13', '100123_smile01_1', NULL);
|
||||
INSERT INTO `group_buy_order_list` VALUES (39, 'smile02', '51446037', '618887947111', 100123, '2025-06-19 10:19:40', '2025-07-31 10:19:40', '9890001', 's01', 'c01', 100.00, 20.00, 80.00, 2, '068372097417', '2025-07-25 13:03:36', '2025-07-25 13:05:38', '100123_smile02_1', NULL);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for notify_task
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `notify_task`;
|
||||
CREATE TABLE `notify_task` (
|
||||
`id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID',
|
||||
`activity_id` bigint NOT NULL COMMENT '活动ID',
|
||||
`team_id` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '拼单组队ID',
|
||||
`notify_type` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'HTTP' COMMENT '回调类型(HTTP、MQ)',
|
||||
`notify_mq` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '回调消息',
|
||||
`notify_url` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '回调接口',
|
||||
`notify_count` int NOT NULL COMMENT '回调次数',
|
||||
`notify_status` tinyint(1) NOT NULL COMMENT '回调状态【0初始、1完成、2重试、3失败】',
|
||||
`parameter_json` varchar(256) 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 '更新时间',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `uq_team_id`(`team_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of notify_task
|
||||
-- ----------------------------
|
||||
INSERT INTO `notify_task` VALUES (7, 100124, '92219797', 'MQ', 'topic.team_success', NULL, 1, 1, '{\"teamId\":\"92219797\",\"outTradeNoList\":[\"334152190173\"]}', '2025-07-19 18:08:55', '2025-07-19 18:08:55');
|
||||
|
||||
-- ----------------------------
|
||||
-- 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 = 1 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;
|
@ -41,7 +41,7 @@
|
||||
select user_id, team_id, order_id, activity_id, start_time,
|
||||
end_time, goods_id, source, channel, original_price, deduction_price, pay_price, status
|
||||
from group_buy_order_list
|
||||
where out_trade_no = #{outTradeNo} and user_id = #{userId} and status = 0
|
||||
where out_trade_no = #{outTradeNo} and user_id = #{userId}
|
||||
</select>
|
||||
|
||||
<select id="queryOrderCountByActivityId" parameterType="edu.whut.infrastructure.dao.po.GroupBuyOrderList" resultType="java.lang.Integer">
|
||||
@ -55,6 +55,15 @@
|
||||
where out_trade_no = #{outTradeNo} and user_id = #{userId}
|
||||
</update>
|
||||
|
||||
<update id="unpaid2Refund" parameterType="edu.whut.infrastructure.dao.po.GroupBuyOrderList">
|
||||
update group_buy_order_list
|
||||
set status = 2, update_time = now()
|
||||
where
|
||||
user_id = #{userId} and
|
||||
order_id = #{orderId} and
|
||||
status = 0
|
||||
</update>
|
||||
|
||||
<select id="queryGroupBuyCompleteOrderOutTradeNoListByTeamId" parameterType="java.lang.String" resultType="java.lang.String">
|
||||
select out_trade_no from group_buy_order_list where team_id = #{teamId} and status = 1
|
||||
</select>
|
||||
|
@ -62,6 +62,14 @@
|
||||
where team_id = #{teamId} and status = 0
|
||||
</update>
|
||||
|
||||
<update id="unpaid2Refund" parameterType="edu.whut.infrastructure.dao.po.GroupBuyOrder">
|
||||
update group_buy_order
|
||||
set lock_count = lock_count + #{lockCount}, update_time= now()
|
||||
where
|
||||
team_id = #{teamId} and
|
||||
status = 0
|
||||
</update>
|
||||
|
||||
<select id="queryGroupBuyProgress" parameterType="java.lang.String" resultMap="dataMap">
|
||||
select target_count, complete_count, lock_count from group_buy_order
|
||||
where team_id = #{teamId}
|
||||
|
@ -0,0 +1,40 @@
|
||||
package edu.whut.test.domain.trade;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import edu.whut.domain.trade.model.entity.TradeRefundBehaviorEntity;
|
||||
import edu.whut.domain.trade.model.entity.TradeRefundCommandEntity;
|
||||
import edu.whut.domain.trade.service.ITradeRefundOrderService;
|
||||
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 ITradeRefundOrderServiceTest {
|
||||
|
||||
@Resource
|
||||
private ITradeRefundOrderService tradeRefundOrderService;
|
||||
|
||||
@Test
|
||||
public void test_refundOrder() {
|
||||
TradeRefundCommandEntity tradeRefundCommandEntity = TradeRefundCommandEntity.builder()
|
||||
.userId("smile02")
|
||||
.outTradeNo("068372097417")
|
||||
.source("s01")
|
||||
.channel("c01")
|
||||
.build();
|
||||
|
||||
TradeRefundBehaviorEntity tradeRefundBehaviorEntity = tradeRefundOrderService.refundOrder(tradeRefundCommandEntity);
|
||||
|
||||
log.info("请求参数:{}", JSON.toJSONString(tradeRefundCommandEntity));
|
||||
log.info("测试结果:{}", JSON.toJSONString(tradeRefundBehaviorEntity));
|
||||
}
|
||||
|
||||
}
|
@ -67,8 +67,8 @@ public class MarketTradeControllerTest {
|
||||
@Test
|
||||
public void test_lockMarketPayOrder_teamId_not_null() {
|
||||
LockMarketPayOrderRequestDTO lockMarketPayOrderRequestDTO = new LockMarketPayOrderRequestDTO();
|
||||
lockMarketPayOrderRequestDTO.setUserId("smile03");
|
||||
lockMarketPayOrderRequestDTO.setTeamId("60683575");
|
||||
lockMarketPayOrderRequestDTO.setUserId("smile02");
|
||||
lockMarketPayOrderRequestDTO.setTeamId("51446037");
|
||||
lockMarketPayOrderRequestDTO.setActivityId(100123L);
|
||||
lockMarketPayOrderRequestDTO.setGoodsId("9890001");
|
||||
lockMarketPayOrderRequestDTO.setSource("s01");
|
||||
|
@ -1,6 +1,7 @@
|
||||
package edu.whut.domain.trade.adapter.repository;
|
||||
|
||||
import edu.whut.domain.trade.model.aggregate.GroupBuyOrderAggregate;
|
||||
import edu.whut.domain.trade.model.aggregate.GroupBuyRefundAggregate;
|
||||
import edu.whut.domain.trade.model.aggregate.GroupBuyTeamSettlementAggregate;
|
||||
import edu.whut.domain.trade.model.entity.GroupBuyActivityEntity;
|
||||
import edu.whut.domain.trade.model.entity.GroupBuyTeamEntity;
|
||||
@ -44,4 +45,6 @@ public interface ITradeRepository {
|
||||
boolean occupyTeamStock(String teamStockKey, String recoveryTeamStockKey, Integer target, Integer validTime);
|
||||
|
||||
void recoveryTeamStock(String recoveryTeamStockKey, Integer validTime);
|
||||
|
||||
void unpaid2Refund(GroupBuyRefundAggregate groupBuyRefundAggregate);
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
package edu.whut.domain.trade.model.aggregate;
|
||||
|
||||
import edu.whut.domain.trade.model.entity.TradeRefundOrderEntity;
|
||||
import edu.whut.domain.trade.model.valobj.GroupBuyProgressVO;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 拼团退单聚合
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class GroupBuyRefundAggregate {
|
||||
|
||||
/**
|
||||
* 交易退单
|
||||
*/
|
||||
private TradeRefundOrderEntity tradeRefundOrderEntity;
|
||||
|
||||
/**
|
||||
* 退单进度
|
||||
*/
|
||||
private GroupBuyProgressVO groupBuyProgress;
|
||||
|
||||
public static GroupBuyRefundAggregate buildUnpaid2RefundAggregate(TradeRefundOrderEntity tradeRefundOrderEntity, Integer lockCount) {
|
||||
GroupBuyRefundAggregate groupBuyRefundAggregate = new GroupBuyRefundAggregate();
|
||||
groupBuyRefundAggregate.setTradeRefundOrderEntity(tradeRefundOrderEntity);
|
||||
groupBuyRefundAggregate.setGroupBuyProgress(
|
||||
GroupBuyProgressVO.builder()
|
||||
.lockCount(lockCount)
|
||||
.build());
|
||||
return groupBuyRefundAggregate;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package edu.whut.domain.trade.model.entity;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* 退单行动
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class TradeRefundBehaviorEntity {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 订单ID
|
||||
*/
|
||||
private String orderId;
|
||||
|
||||
/**
|
||||
* 组队ID
|
||||
*/
|
||||
private String teamId;
|
||||
|
||||
/**
|
||||
* 行为枚举
|
||||
*/
|
||||
private TradeRefundBehaviorEnum tradeRefundBehaviorEnum;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public enum TradeRefundBehaviorEnum {
|
||||
|
||||
SUCCESS("success", "成功"),
|
||||
REPEAT("repeat", "重复"),
|
||||
FAIL("fail", "失败"),
|
||||
;
|
||||
|
||||
private String code;
|
||||
private String info;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
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 TradeRefundCommandEntity {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 外部交易单号
|
||||
*/
|
||||
private String outTradeNo;
|
||||
|
||||
/** 渠道 */
|
||||
private String source;
|
||||
|
||||
/** 来源 */
|
||||
private String channel;
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
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 TradeRefundOrderEntity {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 拼单组队ID
|
||||
*/
|
||||
private String teamId;
|
||||
|
||||
/**
|
||||
* 预购订单ID
|
||||
*/
|
||||
private String orderId;
|
||||
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package edu.whut.domain.trade.model.valobj;
|
||||
|
||||
import edu.whut.types.enums.GroupBuyOrderStatusEnumVO;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 退单类型枚举
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public enum RefundTypeEnumVO {
|
||||
|
||||
UNPAID_UNLOCK("unpaid_unlock", "unpaid2RefundStrategy", "未支付,未成团") {
|
||||
@Override
|
||||
public boolean matches(GroupBuyOrderStatusEnumVO groupBuyOrderStatusEnumVO, TradeOrderStatusEnumVO tradeOrderStatusEnumVO) {
|
||||
return GroupBuyOrderStatusEnumVO.PROGRESS.equals(groupBuyOrderStatusEnumVO) && TradeOrderStatusEnumVO.CREATE.equals(tradeOrderStatusEnumVO);
|
||||
}
|
||||
},
|
||||
|
||||
PAID_UNFORMED("paid_unformed", "paid2RefundStrategy", "已支付,未成团") {
|
||||
@Override
|
||||
public boolean matches(GroupBuyOrderStatusEnumVO groupBuyOrderStatusEnumVO, TradeOrderStatusEnumVO tradeOrderStatusEnumVO) {
|
||||
return GroupBuyOrderStatusEnumVO.PROGRESS.equals(groupBuyOrderStatusEnumVO) && TradeOrderStatusEnumVO.COMPLETE.equals(tradeOrderStatusEnumVO);
|
||||
}
|
||||
},
|
||||
|
||||
PAID_FORMED("paid_formed", "paidTeam2RefundStrategy", "已支付,已成团") {
|
||||
@Override
|
||||
public boolean matches(GroupBuyOrderStatusEnumVO groupBuyOrderStatusEnumVO, TradeOrderStatusEnumVO tradeOrderStatusEnumVO) {
|
||||
return GroupBuyOrderStatusEnumVO.COMPLETE.equals(groupBuyOrderStatusEnumVO) && TradeOrderStatusEnumVO.COMPLETE.equals(tradeOrderStatusEnumVO);
|
||||
}
|
||||
},
|
||||
;
|
||||
|
||||
private String code;
|
||||
private String strategy;
|
||||
private String info;
|
||||
|
||||
/**
|
||||
* 抽象方法,由每个枚举值实现自己的匹配逻辑
|
||||
*/
|
||||
public abstract boolean matches(GroupBuyOrderStatusEnumVO groupBuyOrderStatusEnumVO, TradeOrderStatusEnumVO tradeOrderStatusEnumVO);
|
||||
|
||||
/**
|
||||
* 根据状态组合获取对应的退款策略枚举
|
||||
*/
|
||||
public static RefundTypeEnumVO getRefundStrategy(GroupBuyOrderStatusEnumVO groupBuyOrderStatusEnumVO, TradeOrderStatusEnumVO tradeOrderStatusEnumVO) {
|
||||
return Arrays.stream(values())
|
||||
.filter(refundType -> refundType.matches(groupBuyOrderStatusEnumVO, tradeOrderStatusEnumVO))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new RuntimeException("不支持的退款状态组合: groupBuyOrderStatus=" + groupBuyOrderStatusEnumVO + ", tradeOrderStatus=" + tradeOrderStatusEnumVO));
|
||||
}
|
||||
|
||||
public static RefundTypeEnumVO valueOf(Integer code) {
|
||||
switch (code) {
|
||||
case 1:
|
||||
return UNPAID_UNLOCK;
|
||||
case 2:
|
||||
return PAID_UNFORMED;
|
||||
case 3:
|
||||
return PAID_FORMED;
|
||||
}
|
||||
throw new RuntimeException("退单类型枚举值不存在: " + code);
|
||||
}
|
||||
|
||||
}
|
@ -14,7 +14,8 @@ public enum TradeOrderStatusEnumVO {
|
||||
|
||||
CREATE(0, "初始创建"),
|
||||
COMPLETE(1, "消费完成"),
|
||||
CLOSE(2, "超时关单"),
|
||||
CLOSE(2, "用户退单"),
|
||||
TIME_OUT(2,"超时退单")
|
||||
;
|
||||
|
||||
private Integer code;
|
||||
|
@ -0,0 +1,14 @@
|
||||
package edu.whut.domain.trade.service;
|
||||
|
||||
|
||||
import edu.whut.domain.trade.model.entity.TradeRefundBehaviorEntity;
|
||||
import edu.whut.domain.trade.model.entity.TradeRefundCommandEntity;
|
||||
|
||||
/**
|
||||
* 退单,逆向流程接口
|
||||
*/
|
||||
public interface ITradeRefundOrderService {
|
||||
|
||||
TradeRefundBehaviorEntity refundOrder(TradeRefundCommandEntity tradeRefundCommandEntity);
|
||||
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package edu.whut.domain.trade.service.refund;
|
||||
|
||||
import edu.whut.domain.trade.adapter.repository.ITradeRepository;
|
||||
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.ITradeRefundOrderService;
|
||||
import edu.whut.domain.trade.service.refund.business.IRefundOrderStrategy;
|
||||
import edu.whut.types.enums.GroupBuyOrderStatusEnumVO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 退单,逆向流程服务
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class TradeRefundOrderService implements ITradeRefundOrderService {
|
||||
|
||||
private final ITradeRepository repository;
|
||||
|
||||
private final Map<String, IRefundOrderStrategy> refundOrderStrategyMap;
|
||||
|
||||
@Override
|
||||
public TradeRefundBehaviorEntity refundOrder(TradeRefundCommandEntity tradeRefundCommandEntity) {
|
||||
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)
|
||||
.build());
|
||||
|
||||
return TradeRefundBehaviorEntity.builder()
|
||||
.userId(tradeRefundCommandEntity.getUserId())
|
||||
.orderId(orderId)
|
||||
.teamId(teamId)
|
||||
.tradeRefundBehaviorEnum(TradeRefundBehaviorEntity.TradeRefundBehaviorEnum.SUCCESS)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package edu.whut.domain.trade.service.refund.business;
|
||||
|
||||
import edu.whut.domain.trade.model.entity.TradeRefundOrderEntity;
|
||||
|
||||
/**
|
||||
* 退单策略接口
|
||||
* 未支付,Unpaid
|
||||
* 未成团,UnformedTeam
|
||||
* 已成团,AlreadyFormedTeam
|
||||
*/
|
||||
public interface IRefundOrderStrategy {
|
||||
|
||||
void refundOrder(TradeRefundOrderEntity tradeRefundOrderEntity);
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package edu.whut.domain.trade.service.refund.business.impl;
|
||||
|
||||
import edu.whut.domain.trade.model.entity.TradeRefundOrderEntity;
|
||||
import edu.whut.domain.trade.service.refund.business.IRefundOrderStrategy;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 发起退单(未成团&已支付),锁单量-1、完成量-1、组队订单状态更新、发送退单消息(MQ)
|
||||
*/
|
||||
@Slf4j
|
||||
@Service("paid2RefundStrategy")
|
||||
public class Paid2RefundStrategy implements IRefundOrderStrategy {
|
||||
|
||||
@Override
|
||||
public void refundOrder(TradeRefundOrderEntity tradeRefundOrderEntity) {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package edu.whut.domain.trade.service.refund.business.impl;
|
||||
|
||||
import edu.whut.domain.trade.model.entity.TradeRefundOrderEntity;
|
||||
import edu.whut.domain.trade.service.refund.business.IRefundOrderStrategy;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 发起退单(已成团&已支付),锁单量-1、完成量-1、组队订单状态更新、发送退单消息(MQ)
|
||||
*/
|
||||
@Slf4j
|
||||
@Service("paidTeam2RefundStrategy")
|
||||
public class PaidTeam2RefundStrategy implements IRefundOrderStrategy {
|
||||
|
||||
@Override
|
||||
public void refundOrder(TradeRefundOrderEntity tradeRefundOrderEntity) {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package edu.whut.domain.trade.service.refund.business.impl;
|
||||
|
||||
import edu.whut.domain.trade.adapter.repository.ITradeRepository;
|
||||
import edu.whut.domain.trade.model.aggregate.GroupBuyRefundAggregate;
|
||||
import edu.whut.domain.trade.model.entity.TradeRefundOrderEntity;
|
||||
import edu.whut.domain.trade.service.refund.business.IRefundOrderStrategy;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 未支付,未成团;发起退单(未支付),锁单量-1、组队订单状态更新
|
||||
*/
|
||||
@Slf4j
|
||||
@Service("unpaid2RefundStrategy")
|
||||
public class Unpaid2RefundStrategy implements IRefundOrderStrategy {
|
||||
|
||||
@Resource
|
||||
private ITradeRepository repository;
|
||||
|
||||
/**
|
||||
* 用户未支付的退单流程,仅需更新订单状态为已退单,释放lockcount锁单量
|
||||
*/
|
||||
@Override
|
||||
public void refundOrder(TradeRefundOrderEntity tradeRefundOrderEntity) {
|
||||
log.info("退单;未支付,未成团 userId:{} teamId:{} orderId:{}", tradeRefundOrderEntity.getUserId(), tradeRefundOrderEntity.getTeamId(), tradeRefundOrderEntity.getOrderId());
|
||||
repository.unpaid2Refund(GroupBuyRefundAggregate.buildUnpaid2RefundAggregate(tradeRefundOrderEntity, -1));
|
||||
}
|
||||
|
||||
}
|
@ -3,6 +3,7 @@ import edu.whut.domain.trade.adapter.repository.ITradeRepository;
|
||||
import edu.whut.domain.trade.model.entity.MarketPayOrderEntity;
|
||||
import edu.whut.domain.trade.model.entity.TradeSettlementRuleCommandEntity;
|
||||
import edu.whut.domain.trade.model.entity.TradeSettlementRuleFilterBackEntity;
|
||||
import edu.whut.domain.trade.model.valobj.TradeOrderStatusEnumVO;
|
||||
import edu.whut.domain.trade.service.settlement.factory.TradeSettlementRuleFilterFactory;
|
||||
import edu.whut.types.design.framework.link.model2.handler.ILogicHandler;
|
||||
import edu.whut.types.enums.ResponseCode;
|
||||
@ -29,7 +30,7 @@ public class OutTradeNoRuleFilter implements ILogicHandler<TradeSettlementRuleCo
|
||||
// 查询拼团信息
|
||||
MarketPayOrderEntity marketPayOrderEntity = repository.queryMarketPayOrderEntityByOutTradeNo(requestParameter.getUserId(), requestParameter.getOutTradeNo());
|
||||
|
||||
if (null == marketPayOrderEntity) {
|
||||
if (null == marketPayOrderEntity || TradeOrderStatusEnumVO.CLOSE.equals(marketPayOrderEntity.getTradeOrderStatusEnumVO())) {
|
||||
log.error("不存在的外部交易单号或用户已退单,不需要做支付订单结算:{} outTradeNo:{}", requestParameter.getUserId(), requestParameter.getOutTradeNo());
|
||||
throw new AppException(ResponseCode.E0104);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ 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.GroupBuyRefundAggregate;
|
||||
import edu.whut.domain.trade.model.aggregate.GroupBuyTeamSettlementAggregate;
|
||||
import edu.whut.domain.trade.model.entity.*;
|
||||
import edu.whut.domain.trade.model.valobj.GroupBuyProgressVO;
|
||||
@ -259,9 +260,9 @@ public class TradeRepository implements ITradeRepository {
|
||||
* 更新明细表状态 → COMPLETE
|
||||
* 更新主表 complete_count + 1
|
||||
* 当达到 targetCount 时,更新主表状态 → COMPLETE 并写入回调任务
|
||||
* 整体包裹在 500ms 事务内,任何一步失败都会回滚。
|
||||
* 整体包裹在 5000ms 事务内,任何一步失败都会回滚。
|
||||
*/
|
||||
@Transactional(timeout = 500)
|
||||
@Transactional(timeout = 5000)
|
||||
@Override
|
||||
public NotifyTaskEntity settlementMarketPayOrder(GroupBuyTeamSettlementAggregate agg) {
|
||||
|
||||
@ -446,4 +447,37 @@ public class TradeRepository implements ITradeRepository {
|
||||
|
||||
redisService.incr(recoveryteamOccupiedStockKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户未支付的退单,在一个事务内完成,因为要同时修改两张表
|
||||
*/
|
||||
@Override
|
||||
@Transactional(timeout = 5000)
|
||||
public void unpaid2Refund(GroupBuyRefundAggregate groupBuyRefundAggregate) {
|
||||
TradeRefundOrderEntity tradeRefundOrderEntity = groupBuyRefundAggregate.getTradeRefundOrderEntity();
|
||||
GroupBuyProgressVO groupBuyProgress = groupBuyRefundAggregate.getGroupBuyProgress();
|
||||
|
||||
GroupBuyOrderList groupBuyOrderListReq = new GroupBuyOrderList();
|
||||
// 保留userId,企业中往往会根据 userId 作为分库分表路由键,如果将来做分库分表也可以方便处理
|
||||
groupBuyOrderListReq.setUserId(tradeRefundOrderEntity.getUserId());
|
||||
groupBuyOrderListReq.setOrderId(tradeRefundOrderEntity.getOrderId());
|
||||
|
||||
int updateUnpaid2RefundCount = groupBuyOrderListDao.unpaid2Refund(groupBuyOrderListReq);
|
||||
if (1 != updateUnpaid2RefundCount) {
|
||||
log.error("逆向流程,更新订单状态(退单)失败 {} {}", tradeRefundOrderEntity.getUserId(), tradeRefundOrderEntity.getOrderId());
|
||||
throw new AppException(ResponseCode.UPDATE_ZERO);
|
||||
}
|
||||
|
||||
GroupBuyOrder groupBuyOrderReq = new GroupBuyOrder();
|
||||
groupBuyOrderReq.setTeamId(tradeRefundOrderEntity.getTeamId());
|
||||
groupBuyOrderReq.setLockCount(groupBuyProgress.getLockCount());
|
||||
|
||||
int updateTeamUnpaid2Refund = groupBuyOrderDao.unpaid2Refund(groupBuyOrderReq);
|
||||
if (1 != updateTeamUnpaid2Refund) {
|
||||
log.error("逆向流程,更新组队记录(退单)失败 {} {}", tradeRefundOrderEntity.getUserId(), tradeRefundOrderEntity.getOrderId());
|
||||
throw new AppException(ResponseCode.UPDATE_ZERO);
|
||||
}
|
||||
|
||||
// 逆向后,还要处理 redis recoveryCount 恢复了,这部分最后统一处理
|
||||
}
|
||||
}
|
||||
|
@ -52,4 +52,9 @@ public interface IGroupBuyOrderDao {
|
||||
List<String> queryActiveTeamIdsByActivityId(Long activityId);
|
||||
|
||||
Integer queryInUserCount(@Param("teamIds") Set<String> teamIdSet);
|
||||
|
||||
/**
|
||||
* 未支付退单
|
||||
*/
|
||||
int unpaid2Refund(GroupBuyOrder groupBuyOrderReq);
|
||||
}
|
||||
|
@ -29,4 +29,8 @@ public interface IGroupBuyOrderListDao {
|
||||
|
||||
List<GroupBuyOrderList> queryInProgressUserGroupBuyOrderDetailListByRandom(GroupBuyOrderList groupBuyOrderListReq);
|
||||
|
||||
/**
|
||||
* 未支付退单
|
||||
*/
|
||||
int unpaid2Refund(GroupBuyOrderList groupBuyOrderListReq);
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import edu.whut.domain.trade.model.entity.*;
|
||||
import edu.whut.domain.trade.model.valobj.GroupBuyProgressVO;
|
||||
import edu.whut.domain.trade.model.valobj.NotifyConfigVO;
|
||||
import edu.whut.domain.trade.model.valobj.NotifyTypeEnumVO;
|
||||
import edu.whut.domain.trade.model.valobj.TradeOrderStatusEnumVO;
|
||||
import edu.whut.domain.trade.service.ITradeLockOrderService;
|
||||
import edu.whut.domain.trade.service.ITradeSettlementOrderService;
|
||||
import edu.whut.types.enums.ResponseCode;
|
||||
@ -93,7 +94,7 @@ public class MarketTradeController implements IMarketTradeService {
|
||||
/* ---------- 2. 查询是否已存在未支付锁单 ---------- */
|
||||
MarketPayOrderEntity marketPayOrderEntity =
|
||||
tradeOrderService.queryNoPayMarketPayOrderByOutTradeNo(userId, outTradeNo);
|
||||
if (marketPayOrderEntity != null) {
|
||||
if (marketPayOrderEntity != null && TradeOrderStatusEnumVO.CREATE.equals(marketPayOrderEntity.getTradeOrderStatusEnumVO())) {
|
||||
// 若已锁单未支付,直接返回原锁单信息(幂等)
|
||||
return buildSuccessResp(marketPayOrderEntity);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user