|
|
@@ -0,0 +1,403 @@
|
|
|
+# Feature Specification: 商家促销 + 优惠券系统
|
|
|
+
|
|
|
+**Feature Branch**: `008-promotion-coupon`
|
|
|
+**Created**: 2026-05-29
|
|
|
+**Status**: Draft
|
|
|
+**Input**: 参考美团外卖商家端营销活动机制,为 foodie 系统实现促销和优惠券功能
|
|
|
+
|
|
|
+## 背景
|
|
|
+
|
|
|
+foodie 系统目前缺少商家端的营销工具。商家无法设置满减、折扣等促销活动,也无法发放优惠券。需要参考美团外卖的机制,实现一套适合 foodie 的促销 + 优惠券系统。
|
|
|
+
|
|
|
+### 旧代码处理
|
|
|
+
|
|
|
+系统中已有旧的促销/优惠券代码,**全部废弃不使用,不修改**:
|
|
|
+
|
|
|
+| 旧代码 | 位置 | 说明 |
|
|
|
+|--------|------|------|
|
|
|
+| `SalesPromotion.java` | ruoyi-system/domain | 旧促销活动实体,表 `sales_promotion` |
|
|
|
+| `VipQuanyi.java` | ruoyi-system/domain | 旧优惠券模板,表 `vip_quanyi` |
|
|
|
+| `VipUserQuanyi.java` | ruoyi-system/domain | 旧用户券,表 `vip_user_quanyi` |
|
|
|
+| `SalesPromotionController` | ruoyi-admin/app/promotion | 平台管理端促销接口 |
|
|
|
+| `ShSalesPromotionController` | ruoyi-admin/app/mendian | 商家端促销接口 |
|
|
|
+| `VipUserQuanyiController` | ruoyi-admin/app/user | 用户端优惠券接口 |
|
|
|
+
|
|
|
+**原则:所有新功能新建文件、新表、新接口,不动旧代码。**
|
|
|
+
|
|
|
+### 新表命名规则
|
|
|
+
|
|
|
+所有新建数据库表使用 `promotion_` 前缀,与旧表区分:
|
|
|
+
|
|
|
+| 新表名 | 说明 |
|
|
|
+|--------|------|
|
|
|
+| `promotion_activity` | 促销活动表(替代旧 `sales_promotion`) |
|
|
|
+| `promotion_activity_rule` | 促销规则明细表 |
|
|
|
+| `promotion_coupon_batch` | 券批次表(替代旧 `vip_quanyi`) |
|
|
|
+| `promotion_coupon_rule` | 券规则表 |
|
|
|
+| `promotion_user_coupon` | 用户券表(替代旧 `vip_user_quanyi`) |
|
|
|
+
|
|
|
+### 工作范围
|
|
|
+
|
|
|
+只有两部分:
|
|
|
+1. **后端 API**(Java/Spring Boot)— 新建 Entity、Mapper、Service、Controller
|
|
|
+2. **商家 PC 端前端**(foodie-store Vue.js)— 促销管理页面 + 优惠券管理页面
|
|
|
+
|
|
|
+用户端(小程序)的领券、下单优惠计算不在本 spec 范围内,后续单独做。
|
|
|
+
|
|
|
+### 美团商家营销活动分类
|
|
|
+
|
|
|
+美团外卖商家端有16种营销活动,分为三类:
|
|
|
+- **促销类**(直接影响价格):满减、折扣商品、第二份半价、新客立减、减配送费、满减运费、爆品
|
|
|
+- **优惠券类**(用户领券后使用):店内领券、店外发券、下单返券、集点返券、收藏有礼、售卖代金券
|
|
|
+- **其他营销**:满赠、买赠、超值换购、好友助力、美团会员红包
|
|
|
+
|
|
|
+### foodie 范围裁剪
|
|
|
+
|
|
|
+本需求只实现以下功能:
|
|
|
+
|
|
|
+**促销(4种)**:满减、折扣商品(分组折扣)、第二份半价、新客立减
|
|
|
+
|
|
|
+**不做**:爆品、买赠、减配送费、满减运费、好友助力等
|
|
|
+
|
|
|
+**优惠券**:只做"店内领券"一种发放方式
|
|
|
+
|
|
|
+**不做**:店外发券、下单返券、集点返券、收藏有礼、售卖代金券
|
|
|
+
|
|
|
+### 促销的作用对象
|
|
|
+
|
|
|
+促销不是都作用于同一个价格层级:
|
|
|
+
|
|
|
+| 层级 | 作用对象 | 包含的促销类型 |
|
|
|
+|------|---------|-------------|
|
|
|
+| 订单级 | 订单总价 | 满减、新客立减 |
|
|
|
+| 商品级 | 指定商品单价 | 折扣商品、第二份半价 |
|
|
|
+
|
|
|
+### 互斥规则
|
|
|
+
|
|
|
+参考美团做法,用户下单时系统自动计算两条路径,选最优惠的:
|
|
|
+
|
|
|
+- **满减、折扣商品、第二份半价 → 三选一**,系统算两遍自动选最优
|
|
|
+ - 路径A(走折扣):折扣商品按折扣价,非折扣商品原价
|
|
|
+ - 路径B(走满减):所有商品恢复原价,再减满减金额
|
|
|
+- **新客立减** → 可与以上任意一种叠加
|
|
|
+- **互斥在下单时判断**,不限制商家创建活动
|
|
|
+
|
|
|
+### 叠加计算顺序
|
|
|
+
|
|
|
+```
|
|
|
+商品原价 → 促销(满减/折扣/第二份半价,三选一)→ 商家满减券 → 平台券 = 实付金额
|
|
|
+商品券单独作用在指定商品上,不与满减券叠加
|
|
|
+一个订单最多:1个促销 + 1张满减券 + 1张平台券
|
|
|
+```
|
|
|
+
|
|
|
+## User Scenarios & Testing
|
|
|
+
|
|
|
+### User Story 1 - 商家创建促销活动 (Priority: P1)
|
|
|
+
|
|
|
+商家在后台创建促销活动(满减/折扣/第二份半价/新客立减),活动生效后用户下单时自动享受优惠。
|
|
|
+
|
|
|
+**Why this priority**: 促销是商家最核心的营销需求,没有促销就没有优惠,后续优惠券也无法叠加使用。
|
|
|
+
|
|
|
+**Independent Test**: 商家创建一个满减活动(满20减5),用户下单满20元后自动减5元,订单金额正确。
|
|
|
+
|
|
|
+**Acceptance Scenarios**:
|
|
|
+
|
|
|
+1. **Given** 商家未创建任何促销活动, **When** 商家创建满减活动(满20减5 / 满40减12), **Then** 活动列表显示进行中,用户端店铺显示满减标签
|
|
|
+2. **Given** 商家已创建折扣活动(宫保鸡丁7折、麻婆豆腐8折), **When** 用户下单宫保鸡丁(¥20) + 麻婆豆腐(¥18), **Then** 折扣价 ¥14 + ¥14.4 = ¥28.4
|
|
|
+3. **Given** 商家同时有满减(满40减12)和折扣(宫保鸡丁7折¥14), **When** 用户下单宫保鸡丁(¥20) + 鸡腿饭(¥25) = ¥45, **Then** 系统算两遍:走折扣¥39 vs 走满减¥33,自动选满减
|
|
|
+4. **Given** 商家创建新客立减3元 + 满减(满40减12), **When** 新用户下单¥45, **Then** 先减满减12 = ¥33,再减新客立减3 = ¥30
|
|
|
+5. **Given** 折扣活动采用分组折扣, **When** 商家先建"4折区"和"7折区",把可乐拖入4折区、宫保鸡丁拖入7折区, **Then** 可乐¥6×0.4=¥2.4,宫保鸡丁¥20×0.7=¥14
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### User Story 2 - 商家创建优惠券 (Priority: P2)
|
|
|
+
|
|
|
+商家创建优惠券(满减券/商品券),设置库存和有效期。用户进店时看到领券区,领取后下单使用。
|
|
|
+
|
|
|
+**Why this priority**: 优惠券在促销基础上进一步促进复购和转化,但依赖促销系统先完成。
|
|
|
+
|
|
|
+**Independent Test**: 商家创建"满30减5"优惠券100张,用户进店领取,下单满30元时选择使用,实付减5元。
|
|
|
+
|
|
|
+**Acceptance Scenarios**:
|
|
|
+
|
|
|
+1. **Given** 商家创建满减券(同享券,满30减5,100张), **When** 用户进店看到领券区并领取, **Then** 用户"我的优惠券"列表显示该券,状态为未使用
|
|
|
+2. **Given** 用户已领取满减券(满30减5)且商家有满减活动(满40减12), **When** 用户下单¥45, **Then** 先减满减12=¥33,再减券5=¥28(同享券可叠加)
|
|
|
+3. **Given** 用户已领取互斥券(满30减5), **When** 用户下单且订单有满减活动, **Then** 互斥券不可与满减叠加,用户只能二选一
|
|
|
+4. **Given** 商家创建商品折扣券(宫保鸡丁5折), **When** 用户下单宫保鸡丁(¥20)并使用该券, **Then** 宫保鸡丁按¥10计算
|
|
|
+5. **Given** 优惠券库存为100张,已领取100张, **When** 新用户进店, **Then** 领券区显示"已领完"
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### User Story 3 - 用户下单时优惠计算和展示 (Priority: P3)
|
|
|
+
|
|
|
+用户在结算页看到优惠明细,系统自动选择最优方案,用户可手动切换。
|
|
|
+
|
|
|
+**Why this priority**: 结算页的优惠展示和计算是用户最终看到的结果,需要在促销和优惠券都完成后实现。
|
|
|
+
|
|
|
+**Independent Test**: 用户选好商品进入结算页,页面展示优惠明细(满减/折扣自动选最优 + 可用券列表),选择券后实付金额实时更新。
|
|
|
+
|
|
|
+**Acceptance Scenarios**:
|
|
|
+
|
|
|
+1. **Given** 商家有满减(满40减12)和折扣(宫保鸡丁7折), **When** 用户进入结算页, **Then** 系统展示两条路径对比,默认选最优
|
|
|
+2. **Given** 用户有3张可用券, **When** 用户点击优惠券行, **Then** 弹出券列表,可用券和不可用券分Tab展示,选中券后金额重算
|
|
|
+3. **Given** 用户选了互斥券, **When** 订单同时有满减活动, **Then** 满减自动取消,金额重新计算
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### Edge Cases
|
|
|
+
|
|
|
+- 商家创建了满减活动后又创建折扣活动,两个同时进行中,用户下单时怎么处理?→ 系统自动算两遍选最优,不限制商家创建
|
|
|
+- 用户领了券但下单时未达到门槛(券要求满30但订单只有25)→ 券在"不可用"Tab显示,提示"未达到¥30"
|
|
|
+- 用户领券后商家修改/下架了该券批次 → 已领取的券仍可使用(按领取时的规则),但不能再领取新券
|
|
|
+- 满减活动设了3个档位,订单金额正好在两个档位之间 → 命中低档位(如¥39命中满20减5而非满40减12)
|
|
|
+- 第二份半价商品用户只买了1件 → 不享受优惠,按原价
|
|
|
+- 商家结束促销活动时,正在进行中的订单 → 不影响已下单的订单,只影响新订单
|
|
|
+- 优惠券过期 → 过期券自动标记为已过期,不可使用
|
|
|
+
|
|
|
+## Requirements
|
|
|
+
|
|
|
+### Functional Requirements
|
|
|
+
|
|
|
+#### 促销活动管理(商家端)
|
|
|
+
|
|
|
+- **FR-001**: 商家 MUST 能创建满减活动,支持设置多个档位(如满20减5 / 满40减12 / 满60减20)
|
|
|
+- **FR-002**: 商家 MUST 能创建折扣商品活动,采用分组折扣方式:先建折扣档位(如4折区/7折区/8折区),再为每个档位分配商品
|
|
|
+- **FR-003**: 商家 MUST 能创建第二份半价活动,从商品列表勾选参加的商品
|
|
|
+- **FR-004**: 商家 MUST 能创建新客立减活动,设置固定减免金额
|
|
|
+- **FR-005**: 商家 MUST 能查看活动列表(进行中/未开始/已结束),能结束进行中的活动
|
|
|
+- **FR-006**: 系统 MUST 展示互斥规则提示:满减、折扣、第二份半价三选一,新客立减可叠加
|
|
|
+
|
|
|
+#### 优惠券管理(商家端)
|
|
|
+
|
|
|
+- **FR-007**: 商家 MUST 能创建满减券,设置同享/互斥属性、使用门槛、减免金额、发放总量、有效天数
|
|
|
+- **FR-008**: 商家 MUST 能创建商品券(折扣券/抵用券),关联指定商品,设置折扣率
|
|
|
+- **FR-009**: 商家 MUST 能查看优惠券列表,展示领取/使用情况、库存
|
|
|
+- **FR-010**: 优惠券发放方式只有一种:店内领券(用户进店时在领券区领取)
|
|
|
+
|
|
|
+#### 用户端
|
|
|
+
|
|
|
+- **FR-011**: 用户 MUST 能在店铺首页看到领券区,展示可领取的优惠券
|
|
|
+- **FR-012**: 用户 MUST 能领取优惠券,每人每批次限领1张
|
|
|
+- **FR-013**: 用户 MUST 能在"我的优惠券"中查看已领取的券(未使用/已使用/已过期)
|
|
|
+- **FR-014**: 用户 MUST 能在结算页看到促销优惠明细(自动选最优方案)
|
|
|
+- **FR-015**: 用户 MUST 能在结算页选择使用/不使用优惠券
|
|
|
+- **FR-016**: 系统 MUST 在结算页自动计算满减和折扣两条路径,默认选最优
|
|
|
+
|
|
|
+#### 算价逻辑
|
|
|
+
|
|
|
+- **FR-017**: 下单时系统 MUST 同时计算两条路径:
|
|
|
+ - 路径A(走折扣):折扣商品按折扣价,非折扣商品原价,再扣券
|
|
|
+ - 路径B(走满减):所有商品恢复原价,扣满减,再扣券
|
|
|
+- **FR-018**: 系统 MUST 默认选择实付金额更低的路径
|
|
|
+- **FR-019**: 用户 MUST 能在结算页手动切换路径
|
|
|
+- **FR-020**: 同享券 MUST 能与满减/折扣叠加使用
|
|
|
+- **FR-021**: 互斥券 MUST 不能与满减/折扣/第二份半价叠加
|
|
|
+- **FR-022**: 一个订单最多使用 1个促销 + 1张满减券 + 1张平台券
|
|
|
+
|
|
|
+### Key Entities
|
|
|
+
|
|
|
+- **促销活动 (store_promotion)**: 商家创建的促销规则,包含类型(满减/折扣/第二份半价/新客立减)、状态、时间范围
|
|
|
+- **促销规则 (store_promotion_rule)**: 促销活动的具体规则数据,一个活动对应多条规则(满减档位/折扣商品/第二份半价商品)
|
|
|
+- **券批次 (store_coupon_batch)**: 优惠券模板,包含券名称、类型、库存、有效期
|
|
|
+- **券规则 (store_coupon_rule)**: 优惠券的使用规则,包含门槛、金额、折扣率、同享/互斥属性
|
|
|
+- **用户券 (user_coupon)**: 用户领取的券实例,绑定用户和门店,记录状态和使用情况
|
|
|
+
|
|
|
+## Data Model
|
|
|
+
|
|
|
+所有新建表使用 `promotion_` 前缀,与旧表(`sales_promotion`、`vip_quanyi`、`vip_user_quanyi`)完全独立。
|
|
|
+
|
|
|
+### promotion_activity — 促销活动表
|
|
|
+
|
|
|
+```sql
|
|
|
+CREATE TABLE promotion_activity (
|
|
|
+ id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
+ store_id BIGINT NOT NULL COMMENT '门店ID',
|
|
|
+ type TINYINT NOT NULL COMMENT '类型: 1=满减 2=折扣 3=第二份半价 4=新客立减',
|
|
|
+ name VARCHAR(100) NOT NULL COMMENT '活动名称',
|
|
|
+ status TINYINT DEFAULT 0 COMMENT '0=未开始 1=进行中 2=已结束',
|
|
|
+ start_time DATETIME NOT NULL COMMENT '开始时间',
|
|
|
+ end_time DATETIME NOT NULL COMMENT '结束时间',
|
|
|
+ create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
+ INDEX idx_store_type (store_id, type)
|
|
|
+) COMMENT '促销活动表';
|
|
|
+```
|
|
|
+
|
|
|
+### promotion_activity_rule — 促销规则明细表
|
|
|
+
|
|
|
+```sql
|
|
|
+CREATE TABLE promotion_activity_rule (
|
|
|
+ id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
+ activity_id BIGINT NOT NULL COMMENT '关联促销活动',
|
|
|
+ product_id BIGINT DEFAULT NULL COMMENT '商品ID(折扣/第二份半价用)',
|
|
|
+ threshold DECIMAL(10,2) DEFAULT NULL COMMENT '满减门槛(满X元)',
|
|
|
+ reduce_amount DECIMAL(10,2) DEFAULT NULL COMMENT '减免金额(满减/新客立减)',
|
|
|
+ discount_rate DECIMAL(3,2) DEFAULT NULL COMMENT '折扣率(0.70=7折 / 0.50=半价)',
|
|
|
+ min_quantity INT DEFAULT NULL COMMENT '最低数量(第二份半价=2)',
|
|
|
+ INDEX idx_activity (activity_id)
|
|
|
+) COMMENT '促销规则明细';
|
|
|
+```
|
|
|
+
|
|
|
+### promotion_coupon_batch — 券批次表(模板)
|
|
|
+
|
|
|
+```sql
|
|
|
+CREATE TABLE promotion_coupon_batch (
|
|
|
+ id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
+ store_id BIGINT NOT NULL COMMENT '门店ID',
|
|
|
+ name VARCHAR(100) NOT NULL COMMENT '券名称',
|
|
|
+ coupon_type TINYINT NOT NULL COMMENT '1=满减券 2=商品券',
|
|
|
+ total_count INT NOT NULL COMMENT '发放总量',
|
|
|
+ remain_count INT NOT NULL COMMENT '剩余数量',
|
|
|
+ received_count INT DEFAULT 0 COMMENT '已领取数量',
|
|
|
+ status TINYINT DEFAULT 0 COMMENT '0=未开始 1=进行中 2=已结束 3=已下架',
|
|
|
+ start_time DATETIME NOT NULL COMMENT '领取开始时间',
|
|
|
+ end_time DATETIME NOT NULL COMMENT '领取结束时间',
|
|
|
+ valid_days INT NOT NULL COMMENT '领取后有效天数',
|
|
|
+ create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
+ INDEX idx_store_status (store_id, status)
|
|
|
+) COMMENT '券批次表(模板)';
|
|
|
+```
|
|
|
+
|
|
|
+### promotion_coupon_rule — 券规则表
|
|
|
+
|
|
|
+```sql
|
|
|
+CREATE TABLE promotion_coupon_rule (
|
|
|
+ id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
+ batch_id BIGINT NOT NULL COMMENT '关联券批次',
|
|
|
+ product_id BIGINT DEFAULT NULL COMMENT '商品ID(商品券用,满减券=NULL)',
|
|
|
+ is_mutex TINYINT DEFAULT 0 COMMENT '0=同享券 1=互斥券(满减券用)',
|
|
|
+ threshold DECIMAL(10,2) DEFAULT NULL COMMENT '使用门槛(满X元可用)',
|
|
|
+ amount DECIMAL(10,2) DEFAULT NULL COMMENT '减免金额(满减券/抵用券)',
|
|
|
+ discount_rate DECIMAL(3,2) DEFAULT NULL COMMENT '折扣率(商品折扣券用)',
|
|
|
+ INDEX idx_batch (batch_id)
|
|
|
+) COMMENT '券规则';
|
|
|
+```
|
|
|
+
|
|
|
+### promotion_user_coupon — 用户券表(实例)
|
|
|
+
|
|
|
+```sql
|
|
|
+CREATE TABLE promotion_user_coupon (
|
|
|
+ id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
+ user_id BIGINT NOT NULL COMMENT '用户ID',
|
|
|
+ batch_id BIGINT NOT NULL COMMENT '券批次ID',
|
|
|
+ store_id BIGINT NOT NULL COMMENT '门店ID',
|
|
|
+ status TINYINT DEFAULT 0 COMMENT '0=未使用 1=已使用 2=已过期 3=冻结',
|
|
|
+ order_id BIGINT DEFAULT NULL COMMENT '使用的订单ID',
|
|
|
+ receive_time DATETIME NOT NULL COMMENT '领取时间',
|
|
|
+ use_time DATETIME DEFAULT NULL COMMENT '使用时间',
|
|
|
+ expire_time DATETIME NOT NULL COMMENT '过期时间',
|
|
|
+ INDEX idx_user_status (user_id, status),
|
|
|
+ INDEX idx_store (store_id)
|
|
|
+) COMMENT '用户领券记录';
|
|
|
+```
|
|
|
+
|
|
|
+### pos_order_promotion — 订单优惠明细表
|
|
|
+
|
|
|
+下单时快照记录每个订单命中的优惠信息,优惠类型级别(每条记录 = 一种优惠),不做 SKU 级分摊。
|
|
|
+
|
|
|
+```sql
|
|
|
+CREATE TABLE pos_order_promotion (
|
|
|
+ id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
+ order_id BIGINT NOT NULL COMMENT '关联订单ID',
|
|
|
+ promo_type TINYINT NOT NULL COMMENT '优惠类型: 1=促销活动 2=商家优惠券',
|
|
|
+ promo_sub_type TINYINT DEFAULT NULL COMMENT '促销子类型: 1=满减 2=折扣 3=第二份半价 4=新客立减 (promo_type=1时有效)',
|
|
|
+ promo_id BIGINT DEFAULT NULL COMMENT '促销活动ID(promo_type=1) 或 券批次ID(promo_type=2)',
|
|
|
+ user_coupon_id BIGINT DEFAULT NULL COMMENT '用户券ID (仅优惠券 promo_type=2 时有值, 关联 promotion_user_coupon.id)',
|
|
|
+ promo_name VARCHAR(200) NOT NULL COMMENT '快照名称: 如"午市满减(满40减12)"',
|
|
|
+ promo_detail VARCHAR(500) DEFAULT NULL COMMENT '快照详情JSON: 如{"threshold":40,"reduce":12}',
|
|
|
+ reduce_amount DECIMAL(10,2) NOT NULL COMMENT '减免金额',
|
|
|
+ path_summary VARCHAR(500) DEFAULT NULL COMMENT '路径对比摘要, 仅第一条记录有值, 如"满减路径¥33 vs 折扣路径¥39, 选择满减"',
|
|
|
+ create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ INDEX idx_order (order_id)
|
|
|
+) COMMENT '订单优惠明细';
|
|
|
+```
|
|
|
+
|
|
|
+#### 字段说明
|
|
|
+
|
|
|
+| 字段 | 作用 | 示例 |
|
|
|
+|------|------|------|
|
|
|
+| `promo_type` | 区分是促销还是优惠券 | 1=促销, 2=优惠券 |
|
|
|
+| `promo_sub_type` | 促销的具体子类型 | 1=满减, 2=折扣, 3=第二份半价, 4=新客立减;优惠券时为 null |
|
|
|
+| `promo_id` | 关联原始活动或券批次 | promo_type=1 时为 promotion_activity.id;promo_type=2 时为 promotion_coupon_batch.id |
|
|
|
+| `user_coupon_id` | 关联用户领取的券实例 | promo_type=2 时为 promotion_user_coupon.id;促销时为 null |
|
|
|
+| `promo_name` | 下单时的快照名称 | "午市满减(满40减12)" |
|
|
|
+| `promo_detail` | 规则快照 JSON | `{"type":"manjian","threshold":40,"reduce":12}` |
|
|
|
+| `reduce_amount` | 实际减免金额 | 12.00 |
|
|
|
+| `path_summary` | 路径对比摘要 | "满减路径¥33 vs 折扣路径¥39, 选择满减",仅第一条记录有值 |
|
|
|
+
|
|
|
+#### 示例数据
|
|
|
+
|
|
|
+订单:宫保鸡丁¥20 + 鸡腿饭¥25 = ¥45,商家有满减(满40减12)和折扣(宫保鸡丁7折),用户有满30减5同享券,新用户
|
|
|
+
|
|
|
+| promo_type | promo_sub_type | promo_name | reduce_amount | path_summary |
|
|
|
+|---|---|---|---|---|
|
|
|
+| 1(促销) | 1(满减) | 午市满减(满40减12) | 12.00 | 满减路径¥33 vs 折扣路径¥39, 选择满减 |
|
|
|
+| 2(优惠券) | null | 满30减5(同享券) | 5.00 | null |
|
|
|
+| 1(促销) | 4(新客立减) | 新客立减 | 3.00 | null |
|
|
|
+
|
|
|
+#### 与 pos_order 现有字段的关系
|
|
|
+
|
|
|
+下单时双写:
|
|
|
+- `pos_order` 的 `mdSalesReduction`、`mdDiscountAmount` 等汇总字段照常写入
|
|
|
+- `pos_order_promotion` 写入每条优惠明细(快照)
|
|
|
+
|
|
|
+查询场景:
|
|
|
+- 订单列表:只看 `pos_order` 汇总字段
|
|
|
+- 订单详情/退款:查 `pos_order_promotion` 获取明细
|
|
|
+
|
|
|
+#### 设计决策
|
|
|
+
|
|
|
+- **单表扁平设计**:一张表存储所有优惠明细,每条记录代表一种优惠,一个订单通常 3-5 条记录
|
|
|
+- **优惠类型级别**:不做 SKU 级优惠分摊,所有优惠都是商家级别
|
|
|
+- **快照机制**:下单时将促销名称、规则、金额拍快照存入,后续促销活动修改不影响已下单的订单
|
|
|
+- **路径对比摘要**:`path_summary` 字段记录系统计算的路径对比结果(如满减 vs 折扣),仅存在该订单的第一条明细记录上,其余记录该字段为 null
|
|
|
+- **pos_order 现有字段保留**:不删除现有的 `mdSalesReduction`、`mdDiscountAmount` 等字段,新表明细作为补充信息
|
|
|
+
|
|
|
+### 表关系
|
|
|
+
|
|
|
+```
|
|
|
+促销模块:
|
|
|
+ promotion_activity 1 → N promotion_activity_rule
|
|
|
+
|
|
|
+优惠券模块:
|
|
|
+ promotion_coupon_batch 1 → 1 promotion_coupon_rule
|
|
|
+ promotion_coupon_batch 1 → N promotion_user_coupon
|
|
|
+
|
|
|
+订单优惠:
|
|
|
+ pos_order 1 → N pos_order_promotion
|
|
|
+ pos_order_promotion N → 1 promotion_activity (promo_type=1 时)
|
|
|
+ pos_order_promotion N → 1 promotion_coupon_batch (promo_type=2 时)
|
|
|
+ pos_order_promotion N → 1 promotion_user_coupon (promo_type=2 时)
|
|
|
+```
|
|
|
+
|
|
|
+## Success Criteria
|
|
|
+
|
|
|
+### Measurable Outcomes
|
|
|
+
|
|
|
+- **SC-001**: 商家能在3分钟内完成一个满减活动的创建(包括设置3个档位)
|
|
|
+- **SC-002**: 商家能在3分钟内完成一个分组折扣活动的创建(建2个档位 + 分配5个商品)
|
|
|
+- **SC-003**: 商家能在2分钟内完成一张优惠券的创建
|
|
|
+- **SC-004**: 用户下单时优惠计算正确,结算页实时展示优惠明细
|
|
|
+- **SC-005**: 满100%覆盖互斥规则:满减/折扣/第二份半价三选一,新客立减可叠加
|
|
|
+
|
|
|
+## Assumptions
|
|
|
+
|
|
|
+- **旧代码不动**:`SalesPromotion`、`VipQuanyi`、`VipUserQuanyi` 等旧实体和旧接口全部废弃,新功能完全新建文件
|
|
|
+- **新表前缀 `promotion_`**:与旧表(`sales_promotion`、`vip_quanyi`)完全独立
|
|
|
+- **工作范围**:只有后端 API + 商家 PC 端前端(foodie-store)
|
|
|
+- **用户端不在本范围**:小程序端的领券、下单优惠计算、结算页展示后续单独做
|
|
|
+- 促销和优惠券都是门店级别(storeId),不是跨店通用
|
|
|
+- `pos_order_promotion`(订单优惠明细表):下单时快照记录优惠明细,单表扁平设计,优惠类型级别,不做 SKU 分摊。详见 Data Model 章节
|
|
|
+- 现有 `pos_order` 表的优惠汇总字段(`mdSalesReduction`、`mdDiscountAmount` 等)保留不动,新表明细作为补充
|
|
|
+- 平台券不在本需求范围内,只做商家级促销和商家券
|
|
|
+- SQL 变更写入 `updatesql/sql.md`,由开发者手动执行
|
|
|
+
|
|
|
+## 参考资源
|
|
|
+
|
|
|
+- 美团外卖商家活动创建攻略(知乎)
|
|
|
+- 美团外卖优惠规则(官方)
|
|
|
+- 美团外卖平台市场营销规则(rules-center.meituan.com)
|
|
|
+- 优惠券系统设计(知乎)
|
|
|
+- 大厂优惠券系统设计(掘金)
|
|
|
+- Demo文件:`meituan-promotion-types-demo.html`、`merchant-promotion-ui-demo.html`、`meituan-checkout-demo.html`
|