From d7a6b7cc9418df273c0807fd69fec8904e5ec393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Tue, 3 Feb 2026 20:37:11 +0800 Subject: [PATCH] =?UTF-8?q?feat(ticket):=20=E5=AE=9E=E7=8E=B0=E5=A5=97?= =?UTF-8?q?=E7=A5=A8=E5=88=86=E6=9C=9F=E9=87=8A=E6=94=BE=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E6=A0=B8=E5=BF=83=E6=95=B0=E6=8D=AE=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改 GltUserTicketReleaseParam 中 id 和 userTicketId 类型从 Long 改为 Integer - 移除 ShopOrderServiceImpl 中的 shopTicketBizService 依赖注入 - 注释掉订单支付成功后的套票发放调用 - 添加套票功能开发计划文档,定义套票模板、用户套票账户、释放计划和变更流水的核心概念 - 设计并创建套票相关数据库表,包括套票模板表、用户套票账户表、释放计划表和变更流水表 --- docs/TICKET_PACKAGE_FEATURE_PLAN.md | 31 +++++ docs/TICKET_PACKAGE_TABLES.sql | 121 ++++++++++++++++++ .../glt/param/GltUserTicketReleaseParam.java | 4 +- .../service/impl/ShopOrderServiceImpl.java | 4 +- 4 files changed, 155 insertions(+), 5 deletions(-) create mode 100644 docs/TICKET_PACKAGE_FEATURE_PLAN.md create mode 100644 docs/TICKET_PACKAGE_TABLES.sql diff --git a/docs/TICKET_PACKAGE_FEATURE_PLAN.md b/docs/TICKET_PACKAGE_FEATURE_PLAN.md new file mode 100644 index 0000000..73dac07 --- /dev/null +++ b/docs/TICKET_PACKAGE_FEATURE_PLAN.md @@ -0,0 +1,31 @@ +# 套票(冻结/可用、分期释放)功能开发计划 + +## 目标 +- 为“买N送M(例如买1送4)、起售(例如20桶起售)、按月释放(例如每月释放10桶)、可用未用完叠加”的套票/权益,提供后端可配置、可发放、可释放、可消费的能力。 + +## 核心概念 +- 套票模板:按商品(goodsId)配置买赠规则、起售/起送、释放规则(每期释放数或释放期数)、首期释放时机。 +- 用户套票账户:记录总量、可用量、冻结量、已用量、已释放量;绑定订单(用于幂等与追溯)。 +- 释放计划:每期一条,到期后把冻结转可用(可用未用完自然叠加)。 +- 变更流水:发放/释放/消费等都记录流水,便于对账与排查。 + +## 关键默认规则(可在模板里改) +- 仅赠送量进入套票账户(默认不包含“购买量”本身);如需“买20送80=总100”,可在模板设置 `includeBuyQty=true`。 +- 首期释放:默认“支付成功当日/当刻”释放(`firstReleaseMode=0`);如需“下个月同日释放”,设 `firstReleaseMode=1`。 +- 每期释放:默认按 `monthlyReleaseQty`;如配置了 `releasePeriods`,则平均分摊并处理余数。 + +## 开发步骤(建议按顺序) +1. 需求确认与接入点确认(订单哪个节点发放、桶票如何消费/核销、退款是否回滚、释放日期规则)。 +2. 数据表设计与SQL输出(模板/账户/释放计划/流水)。 +3. 实现套票模板后台CRUD接口。 +4. 支付成功接入:在订单支付成功后发放套票账户+生成释放计划(幂等)。 +5. 定时任务释放:扫描到期释放计划,执行“冻结->可用”转账(幂等)。 +6. 消费扣减:对用户可用量做扣减(支持跨多套票账户FIFO扣减),并落流水。 +7. 测试与验收:至少覆盖(买赠计算、分期拆分、叠加逻辑、幂等、并发扣减)。 + +## 待确认点(不确认也可先按默认实现) +- 套票数量=赠送量?还是(购买量+赠送量)? +- “释放日期”是按支付时间的“日”还是固定每月某一天?(31号跨月如何处理?) +- 退款/取消:是否回滚未使用的可用/冻结?已释放但未用如何处理? +- 消费场景:在哪个业务点扣减(下单抵扣/提货核销/线下核销)? + diff --git a/docs/TICKET_PACKAGE_TABLES.sql b/docs/TICKET_PACKAGE_TABLES.sql new file mode 100644 index 0000000..5e437fe --- /dev/null +++ b/docs/TICKET_PACKAGE_TABLES.sql @@ -0,0 +1,121 @@ +-- 套票(冻结/可用、分期释放)相关表 +-- 说明:项目使用了 MyBatis-Plus 的 tenant 拦截;表内显式保留 tenant_id 字段并建议建立联合唯一索引。 + +-- 1) 套票模板(按商品配置) +CREATE TABLE IF NOT EXISTS shop_ticket_template ( + id INT AUTO_INCREMENT PRIMARY KEY, + goods_id INT NOT NULL, + name VARCHAR(100) NOT NULL, + + enabled TINYINT(1) NOT NULL DEFAULT 1, + unit_name VARCHAR(20) NOT NULL DEFAULT '桶', + + -- 起售/起送 + min_buy_qty INT NOT NULL DEFAULT 1, + start_send_qty INT NOT NULL DEFAULT 1, + + -- 买赠:买1送4 => gift_multiplier=4 + gift_multiplier INT NOT NULL DEFAULT 0, + -- 是否把购买量也计入套票总量(默认仅计入赠送量) + include_buy_qty TINYINT(1) NOT NULL DEFAULT 0, + + -- 释放规则:二选一 + -- A) 每期释放数量(默认每月释放10) + monthly_release_qty INT NOT NULL DEFAULT 10, + -- B) 总共释放多少期(若配置>0,则按期数平均分摊) + release_periods INT NULL, + + -- 首期释放时机:0=支付成功当刻;1=下个月同日 + first_release_mode INT NOT NULL DEFAULT 0, + + comments VARCHAR(255) NULL, + sort_number INT NOT NULL DEFAULT 0, + user_id INT NULL, + + deleted INT NOT NULL DEFAULT 0, + tenant_id INT NOT NULL, + create_time DATETIME NULL, + update_time DATETIME NULL, + + UNIQUE KEY uk_ticket_template_tenant_goods (tenant_id, goods_id), + KEY idx_ticket_template_tenant (tenant_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- 2) 用户套票账户(一次购买通常生成一条) +CREATE TABLE IF NOT EXISTS shop_user_ticket ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + template_id INT NOT NULL, + goods_id INT NOT NULL, + + user_id INT NOT NULL, + order_id INT NULL, + order_no VARCHAR(64) NULL, + order_goods_id INT NULL, + + total_qty INT NOT NULL DEFAULT 0, + available_qty INT NOT NULL DEFAULT 0, + frozen_qty INT NOT NULL DEFAULT 0, + used_qty INT NOT NULL DEFAULT 0, + released_qty INT NOT NULL DEFAULT 0, + + status INT NOT NULL DEFAULT 0, + + deleted INT NOT NULL DEFAULT 0, + tenant_id INT NOT NULL, + create_time DATETIME NULL, + update_time DATETIME NULL, + + KEY idx_user_ticket_user (tenant_id, user_id), + KEY idx_user_ticket_order (tenant_id, order_no), + UNIQUE KEY uk_user_ticket_order_goods (tenant_id, template_id, order_no, order_goods_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- 3) 释放计划/释放记录(每期一条,幂等执行) +CREATE TABLE IF NOT EXISTS shop_user_ticket_release ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + user_ticket_id BIGINT NOT NULL, + user_id INT NOT NULL, + period_no INT NOT NULL, + + release_qty INT NOT NULL, + release_time DATETIME NOT NULL, + + status INT NOT NULL DEFAULT 0, -- 0待释放 1已释放 2作废 + released_time DATETIME NULL, + + tenant_id INT NOT NULL, + create_time DATETIME NULL, + update_time DATETIME NULL, + + UNIQUE KEY uk_ticket_release_period (tenant_id, user_ticket_id, period_no), + KEY idx_ticket_release_due (status, release_time), + KEY idx_ticket_release_user (tenant_id, user_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- 4) 套票变更流水(发放/释放/消费/回滚等) +CREATE TABLE IF NOT EXISTS shop_user_ticket_log ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + user_ticket_id BIGINT NOT NULL, + user_id INT NOT NULL, + + change_type INT NOT NULL, -- 10发放 20释放 30消费 40回滚/退款 + change_available INT NOT NULL DEFAULT 0, + change_frozen INT NOT NULL DEFAULT 0, + change_used INT NOT NULL DEFAULT 0, + + available_after INT NOT NULL DEFAULT 0, + frozen_after INT NOT NULL DEFAULT 0, + used_after INT NOT NULL DEFAULT 0, + + order_id INT NULL, + order_no VARCHAR(64) NULL, + remark VARCHAR(255) NULL, + + tenant_id INT NOT NULL, + create_time DATETIME NULL, + update_time DATETIME NULL, + + KEY idx_ticket_log_user (tenant_id, user_id), + KEY idx_ticket_log_ticket (tenant_id, user_ticket_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + diff --git a/src/main/java/com/gxwebsoft/glt/param/GltUserTicketReleaseParam.java b/src/main/java/com/gxwebsoft/glt/param/GltUserTicketReleaseParam.java index 6237cb4..3ce4bff 100644 --- a/src/main/java/com/gxwebsoft/glt/param/GltUserTicketReleaseParam.java +++ b/src/main/java/com/gxwebsoft/glt/param/GltUserTicketReleaseParam.java @@ -23,10 +23,10 @@ public class GltUserTicketReleaseParam extends BaseParam { private static final long serialVersionUID = 1L; @QueryField(type = QueryType.EQ) - private Long id; + private Integer id; @Schema(description = "水票ID") - private Long userTicketId; + private Integer userTicketId; @Schema(description = "用户ID") @QueryField(type = QueryType.EQ) diff --git a/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java b/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java index 68c16df..9fb8500 100644 --- a/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java +++ b/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java @@ -84,8 +84,6 @@ public class ShopOrderServiceImpl extends ServiceImpl