# IoT Agent Commission Management ## Purpose Manage commission rules and records for IoT agents, supporting three commission types (one-time, long-term, combined), ladder commissions, commission freeze/unfreeze logic, approval workflows, and multi-level agent commission distribution. This capability supports: - Agent hierarchy (tree structure) management - Three commission types: one-time, long-term, combined - Commission rule configuration (series-based for one-time, package-based for long-term) - Combined commission with OR-condition unfreezing (time point OR package cycle) - Ladder commission based on activation/pickup/deposit thresholds - Commission record lifecycle (frozen → unfreezing → released → invalid) - Commission unfreeze conditions (activation + real-name + recharge for normal cards; no real-name required for industry cards) - Commission approval workflow (auto or manual) - Multi-level agent commission distribution ## Requirements ### Requirement: 代理树形关系 系统 SHALL 管理代理的树形层级关系,每个代理只有一个上级代理。 **agent_hierarchies 表**: - `id`: 代理关系 ID(主键,BIGINT) - `agent_id`: 代理用户 ID(BIGINT,唯一) - `parent_agent_id`: 上级代理用户 ID(BIGINT,可空,NULL 表示顶级代理) - `level`: 代理层级(INT,1-顶级代理 2-二级代理 ...) - `path`: 代理路径(VARCHAR(500),如 "1/5/12",用于快速获取整个代理链) - `created_at`: 创建时间(TIMESTAMP,自动填充) - `updated_at`: 更新时间(TIMESTAMP,自动填充) #### Scenario: 创建顶级代理 - **WHEN** 平台创建顶级代理(用户 ID 为 101) - **THEN** 系统创建代理关系记录,`agent_id` 为 101,`parent_agent_id` 为 NULL,`level` 为 1,`path` 为 "101" #### Scenario: 创建下级代理 - **WHEN** 顶级代理(ID 为 101)创建下级代理(用户 ID 为 102) - **THEN** 系统创建代理关系记录,`agent_id` 为 102,`parent_agent_id` 为 101,`level` 为 2,`path` 为 "101/102" #### Scenario: 查询代理的整个上级链 - **WHEN** 查询代理(ID 为 103,路径为 "101/102/103")的上级链 - **THEN** 系统解析 `path` 字段,返回代理 101(顶级)、102(父级)、103(当前代理) --- ### Requirement: 分佣规则配置 系统 SHALL 支持为代理配置分佣规则,包括一次性分佣、长期分佣和组合分佣。 **commission_rules 表**: - `id`: 分佣规则 ID(主键,BIGINT) - `agent_id`: 代理用户 ID(BIGINT) - `business_type`: 业务类型(VARCHAR(20),"iot_card"-IoT卡 | "number_card"-号卡) - `commission_type`: 分佣类型(VARCHAR(20),"one_time"-一次性 | "long_term"-长期 | "combined"-组合) - `series_id`: 套餐系列 ID(BIGINT,可空,**仅一次性分佣使用**,关联 package_series 表) - `package_id`: 套餐 ID(BIGINT,可空,**仅长期分佣使用**,关联 packages 表) - `commission_mode`: 分佣模式(VARCHAR(20),"fixed"-固定金额 | "percent"-百分比) - `commission_value`: 分佣值(DECIMAL(10,4),固定金额或百分比值) - `freeze_days`: 冻结天数(INT,分佣冻结天数,默认 7) - `is_ladder`: 是否阶梯分佣(BOOLEAN,默认 false) - `status`: 规则状态(INT,1-有效 2-无效) - `created_at`: 创建时间(TIMESTAMP,自动填充) - `updated_at`: 更新时间(TIMESTAMP,自动填充) **字段使用规则**: - **一次性分佣**: 使用 `series_id` 关联套餐系列,`package_id` 为 NULL - **长期分佣**: 使用 `package_id` 关联具体套餐,`series_id` 为 NULL - **组合分佣**: 需要创建两条规则记录,一条一次性(使用 `series_id`),一条长期(使用 `package_id`) - **`series_id` 和 `package_id` 互斥**: 不能同时有值 #### Scenario: 配置一次性分佣规则 - **WHEN** 平台为代理(ID 为 123)配置一次性分佣规则,套餐系列 ID 为 1(月套餐系列),固定金额 5.00 元 - **THEN** 系统创建分佣规则,`agent_id` 为 123,`commission_type` 为 "one_time",`series_id` 为 1,`package_id` 为 NULL,`commission_mode` 为 "fixed",`commission_value` 为 5.00 #### Scenario: 配置长期分佣规则 - **WHEN** 平台为代理(ID 为 123)配置长期分佣规则,套餐 ID 为 3001,百分比 5% - **THEN** 系统创建分佣规则,`agent_id` 为 123,`commission_type` 为 "long_term",`series_id` 为 NULL,`package_id` 为 3001,`commission_mode` 为 "percent",`commission_value` 为 0.05 #### Scenario: 配置组合分佣规则 - **WHEN** 平台为代理(ID 为 123)配置组合分佣规则,套餐系列 ID 为 1,先一次性分佣 10.00 元,连续在网 3 个月后开始长期分佣(套餐 ID 为 3001)3.00 元/月 - **THEN** 系统创建两条分佣规则: - 一条 `commission_type` 为 "one_time",`series_id` 为 1,`package_id` 为 NULL - 另一条 `commission_type` 为 "long_term",`series_id` 为 NULL,`package_id` 为 3001,且关联组合条件 #### Scenario: 字段互斥校验 - **WHEN** 平台尝试创建分佣规则,同时设置 `series_id` 为 1 和 `package_id` 为 3001 - **THEN** 系统拒绝创建,返回错误信息"`series_id` 和 `package_id` 不能同时有值" --- ### Requirement: 组合分佣条件配置 系统 SHALL 支持为组合分佣配置解冻条件,包括时间点条件和套餐周期条件。 **commission_combined_conditions 表**: - `id`: 组合条件 ID(主键,BIGINT) - `commission_rule_id`: 关联的分佣规则 ID(BIGINT,必须是 commission_type 为 "long_term" 且属于组合分佣的规则) - `condition_type`: 条件类型(VARCHAR(20),"time_point"-时间点 | "package_cycle"-套餐周期) - `time_months`: 时间月数(INT,可空,仅当 condition_type 为 "time_point" 时有值,表示实名后多少个月) - `package_cycle_threshold`: 套餐周期阈值(INT,可空,仅当 condition_type 为 "package_cycle" 时有值,表示使用多少个套餐周期) - `created_at`: 创建时间(TIMESTAMP,自动填充) - `updated_at`: 更新时间(TIMESTAMP,自动填充) **解冻逻辑**: 组合分佣的长期部分,当满足**任一条件**(OR 关系)时开始产生长期分佣。 #### Scenario: 配置时间点条件 - **WHEN** 平台为组合分佣规则(ID 为 501)配置时间点条件,实名后 3 个月开始长期分佣 - **THEN** 系统创建组合条件记录,`commission_rule_id` 为 501,`condition_type` 为 "time_point",`time_months` 为 3 #### Scenario: 配置套餐周期条件 - **WHEN** 平台为组合分佣规则(ID 为 501)配置套餐周期条件,使用 10 个套餐周期后开始长期分佣 - **THEN** 系统创建组合条件记录,`commission_rule_id` 为 501,`condition_type` 为 "package_cycle",`package_cycle_threshold` 为 10 #### Scenario: 同时配置两种条件(OR 关系) - **WHEN** 平台为组合分佣规则(ID 为 501)同时配置时间点条件(6 个月)和套餐周期条件(10 个周期) - **THEN** 系统创建两条组合条件记录,长期分佣在任一条件满足时开始 --- ### Requirement: 阶梯分佣配置 系统 SHALL 支持阶梯分佣,根据激活量/提货量达到阶梯条件后变更分佣值。 **commission_ladder 表**: - `id`: 阶梯配置 ID(主键,BIGINT) - `commission_rule_id`: 关联的分佣规则 ID(BIGINT) - `ladder_type`: 阶梯类型(VARCHAR(20),"activation"-激活量 | "pickup"-提货量 | "deposit"-保证金) - `ladder_threshold`: 阶梯阈值(INT,如激活 100 张) - `commission_mode`: 分佣模式(VARCHAR(20),"fixed"-固定金额 | "percent"-百分比) - `commission_value`: 分佣值(DECIMAL(10,4),达到阶梯后的分佣值) - `created_at`: 创建时间(TIMESTAMP,自动填充) - `updated_at`: 更新时间(TIMESTAMP,自动填充) #### Scenario: 配置激活量阶梯 - **WHEN** 平台为代理(ID 为 123)配置阶梯分佣,激活 100 张卡后分佣从 5.00 元提升到 8.00 元 - **THEN** 系统创建阶梯配置,`ladder_type` 为 "activation",`ladder_threshold` 为 100,`commission_value` 为 8.00 #### Scenario: 计算阶梯分佣 - **WHEN** 代理(ID 为 123)当月激活量达到 100 张 - **THEN** 系统根据阶梯配置,从第 101 张卡开始使用新的分佣值 8.00 元 --- ### Requirement: 分佣记录管理 系统 SHALL 记录每笔分佣,支持冻结、解冻和发放流程。 **commission_records 表**: - `id`: 分佣记录 ID(主键,BIGINT) - `agent_id`: 代理用户 ID(BIGINT) - `order_id`: 订单 ID(BIGINT) - `commission_rule_id`: 分佣规则 ID(BIGINT) - `commission_type`: 分佣类型(VARCHAR(20),"one_time" | "long_term" | "combined") - `amount`: 分佣金额(DECIMAL(10,2),元) - `status`: 分佣状态(INT,1-冻结 2-解冻中 3-已发放 4-已失效) - `freeze_until`: 冻结截止时间(TIMESTAMP,可空) - `released_at`: 发放时间(TIMESTAMP,可空) - `created_at`: 创建时间(TIMESTAMP,自动填充) - `updated_at`: 更新时间(TIMESTAMP,自动填充) #### Scenario: 创建一次性分佣记录 - **WHEN** 订单(ID 为 10001)完成,触发代理(ID 为 123)的一次性分佣 5.00 元,冻结 7 天 - **THEN** 系统创建分佣记录,`agent_id` 为 123,`order_id` 为 10001,`amount` 为 5.00,状态为 1(冻结),`freeze_until` 为 7 天后 #### Scenario: 分佣自动解冻 - **WHEN** 分佣记录(ID 为 1001)的冻结截止时间到达,且满足解冻条件(激活+实名+充值) - **THEN** 系统将分佣状态从 1(冻结) 变更为 2(解冻中),创建分佣解冻审批记录 #### Scenario: 分佣发放 - **WHEN** 分佣解冻审批通过 - **THEN** 系统将分佣状态从 2(解冻中) 变更为 3(已发放),将分佣金额转入代理钱包,`released_at` 记录发放时间 --- ### Requirement: 分佣解冻条件 系统 SHALL 根据分佣类型校验不同的解冻条件。 **一次性分佣解冻条件**: - 激活(实名状态为已实名;对于行业卡,实名状态可以为未实名) - 达到累计/首次充值金额 - 冻结天数到达 **长期分佣解冻条件**: - 激活(实名状态为已实名;对于行业卡,实名状态可以为未实名) - 达到累计/首次充值金额 - 在网状态正常 - 三无校验通过(通过 Excel 导入解冻) **组合分佣解冻条件**: - **一次性部分**: 立即产生并按一次性分佣条件解冻 - **长期部分**: 当满足以下**任一条件**时开始长期分佣(OR 关系): - 达到某个时间点之后(例如:实名后 3 个月) - **OR** 该 IoT 卡的套餐使用周期数达到阈值(例如:10 个周期) - **注意**: 套餐周期阈值是针对单张 IoT 卡的,不是设备级别 #### Scenario: 一次性分佣满足解冻条件 - **WHEN** 分佣记录(ID 为 1001)的冻结截止时间到达,用户已实名且已充值 - **THEN** 系统将分佣状态变更为 2(解冻中),创建审批记录 #### Scenario: 长期分佣等待 Excel 导入解冻 - **WHEN** 长期分佣记录等待三无校验 - **THEN** 系统保持分佣状态为 1(冻结),等待平台通过 Excel 导入解冻数据 #### Scenario: 组合分佣时间点条件满足 - **WHEN** 组合分佣规则配置为实名后 3 个月开始长期分佣,IoT 卡已实名 3 个月 - **THEN** 系统开始为该 IoT 卡创建长期分佣记录,即使套餐周期数未达到阈值 #### Scenario: 组合分佣套餐周期条件满足 - **WHEN** 组合分佣规则配置为套餐使用 10 个周期后开始长期分佣,IoT 卡已使用套餐 10 个周期 - **THEN** 系统开始为该 IoT 卡创建长期分佣记录,即使未达到时间点要求 #### Scenario: 组合分佣任一条件满足即开始 - **WHEN** 组合分佣规则配置为"实名后 6 个月 OR 10 个套餐周期",IoT 卡已使用 10 个周期但只实名 2 个月 - **THEN** 系统开始为该 IoT 卡创建长期分佣记录(因为套餐周期条件已满足) #### Scenario: 行业卡一次性分佣解冻(无需实名) - **WHEN** 行业卡(card_category 为 "industry")的一次性分佣记录冻结期到达,卡已激活且已充值,但实名状态为未实名 - **THEN** 系统判定解冻条件满足(行业卡无需实名认证),将分佣状态变更为 2(解冻中),创建审批记录 #### Scenario: 行业卡长期分佣解冻(无需实名) - **WHEN** 行业卡(card_category 为 "industry")的长期分佣记录满足充值金额和在网状态,但实名状态为未实名 - **THEN** 系统判定行业卡无需实名认证,等待三无校验通过后可解冻 --- ### Requirement: 分佣解冻审批 系统 SHALL 支持分佣解冻审批流程,审批通过后发放分佣。 **commission_approvals 表**: - `id`: 审批记录 ID(主键,BIGINT) - `commission_record_id`: 分佣记录 ID(BIGINT) - `approval_type`: 审批类型(VARCHAR(20),"auto"-自动 | "manual"-人工) - `status`: 审批状态(INT,1-待审批 2-已通过 3-已拒绝) - `approver_id`: 审批人用户 ID(BIGINT,可空) - `approval_time`: 审批时间(TIMESTAMP,可空) - `approval_note`: 审批备注(TEXT,可空) - `created_at`: 创建时间(TIMESTAMP,自动填充) - `updated_at`: 更新时间(TIMESTAMP,自动填充) #### Scenario: 创建审批记录 - **WHEN** 分佣记录(ID 为 1001)状态变更为 2(解冻中) - **THEN** 系统创建审批记录,`commission_record_id` 为 1001,`approval_type` 为 "auto",状态为 1(待审批) #### Scenario: 审批通过 - **WHEN** 审批人(用户 ID 为 999)审批通过审批记录(ID 为 2001) - **THEN** 系统将审批状态变更为 2(已通过),分佣记录状态变更为 3(已发放),将分佣金额转入代理钱包 #### Scenario: 审批拒绝 - **WHEN** 审批人拒绝审批记录(ID 为 2001),备注"用户未满足在网条件" - **THEN** 系统将审批状态变更为 3(已拒绝),分佣记录状态变更为 4(已失效) --- ### Requirement: 分佣模板 系统 SHALL 支持创建分佣模板,存储常用的分佣方案,便于快速配置。 **commission_templates 表**: - `id`: 模板 ID(主键,BIGINT) - `template_name`: 模板名称(VARCHAR(255)) - `business_type`: 业务类型(VARCHAR(20),"iot_card"-IoT卡 | "number_card"-号卡) - `commission_type`: 分佣类型(VARCHAR(20),"one_time" | "long_term" | "combined") - `commission_mode`: 分佣模式(VARCHAR(20),"fixed" | "percent") - `commission_value`: 分佣值(DECIMAL(10,4)) - `freeze_days`: 冻结天数(INT) - `is_ladder`: 是否阶梯分佣(BOOLEAN) - `created_at`: 创建时间(TIMESTAMP,自动填充) - `updated_at`: 更新时间(TIMESTAMP,自动填充) #### Scenario: 创建分佣模板 - **WHEN** 平台创建分佣模板"标准月套餐分佣",业务类型为 IoT 卡,一次性分佣 5.00 元,冻结 7 天 - **THEN** 系统创建模板记录,`template_name` 为 "标准月套餐分佣",`business_type` 为 "iot_card",`commission_type` 为 "one_time",`commission_value` 为 5.00,`freeze_days` 为 7 #### Scenario: 应用分佣模板 - **WHEN** 平台为代理(ID 为 123)应用模板(ID 为 501) - **THEN** 系统根据模板配置创建分佣规则,`agent_id` 为 123,其他字段从模板复制 --- ### Requirement: 多级代理分佣 系统 SHALL 支持多级代理分佣,根据代理路径计算每一级代理的分佣。 **多级分佣规则**: - 通过代理路径(`path`)获取整个代理链 - 为每一级代理查找对应的分佣规则 - 创建多条分佣记录,每条对应一个代理 #### Scenario: 三级代理分佣 - **WHEN** 订单(ID 为 10001)的代理路径为 "101/102/103",每级代理配置分佣:101(2.00 元)、102(3.00 元)、103(5.00 元) - **THEN** 系统创建 3 条分佣记录:代理 101 的 2.00 元、代理 102 的 3.00 元、代理 103 的 5.00 元 --- ### Requirement: 分佣数据校验 系统 SHALL 对分佣数据进行校验,确保数据完整性和一致性。 **校验规则**: - 代理 ID(agent_id):必填,≥ 1 - 订单 ID(order_id):必填,≥ 1 - 分佣金额(amount):必填,≥ 0,最多 2 位小数 - 分佣状态(status):必填,枚举值 1-4 - 冻结天数(freeze_days):必填,≥ 0 #### Scenario: 创建分佣记录时金额为负数 - **WHEN** 创建分佣记录,金额为 -5.00 - **THEN** 系统拒绝创建,返回错误信息"分佣金额必须 ≥ 0" #### Scenario: 创建分佣规则时分佣值无效 - **WHEN** 创建分佣规则,分佣模式为百分比,分佣值为 1.5(超过 100%) - **THEN** 系统拒绝创建,返回错误信息"百分比分佣值必须在 0-1 之间"