本次提交完成 add-wallet-transfer-tag-models 提案的实施和归档: ## 新增功能模块 - 钱包系统:用户/代理钱包管理,支持充值、扣款、退款、乐观锁防并发 - 换卡记录:物联卡更换历史追溯,包含套餐快照(JSONB) - 标签系统:设备/IoT卡/号卡的统一标签管理 - 运营商渠道:四大运营商(CMCC/CUCC/CTCC/CBN)的渠道管理 ## 数据库变更 - 新增 6 张表:tb_wallet, tb_wallet_transaction, tb_recharge_record, tb_card_replacement_record, tb_tag, tb_resource_tag - 修改 2 张表:tb_carrier(新增渠道字段), tb_order(新增混合支付字段) - 迁移版本:v6 → v7(执行时间 282.5ms) ## 代码变更 - 新增 8 个 Go 模型(符合统一规范:gorm.Model + BaseModel) - 新增 40+ 个常量定义(含完整中文注释) - 新增 7 个 Redis Key 生成函数 - 修复模型规范:移除重复字段,统一使用 gorm.Model 嵌入 ## 文档变更 - 新增 3 个业务文档:数据模型设计、字段说明、迁移验证报告 - 更新 AGENTS.md:新增 Model 模型规范和常量注释规范 - 新增 4 个 OpenSpec 规范:wallet, carrier, card-replacement, tag - 更新 1 个 OpenSpec 规范:iot-order(支持混合支付) ## 验证通过 - ✅ LSP 诊断:所有模型和常量文件无错误 - ✅ OpenSpec 验证:openspec validate --strict 通过 - ✅ 迁移执行:表结构创建成功,索引正确 - ✅ 提案归档:2026-01-13-add-wallet-transfer-tag-models 变更文件统计:29 个文件,新增 3682 行
12 KiB
12 KiB
IoT Order Management
Purpose
Manage orders for IoT card packages and number card products, including order creation, payment processing, status tracking, commission triggering, and support for single-card orders, device-level orders, and carrier number card orders.
This capability supports:
- Unified order entity for package orders and number card orders
- Order status lifecycle management
- Multiple payment methods (wallet, online payment, carrier direct payment)
- Commission triggering on order completion
- Device-level order commission (counted once regardless of bound card count)
- Multi-dimensional order querying and filtering
Requirements
Requirement: 订单实体定义
系统 SHALL 定义订单(Order)实体,统一管理两种订单类型:套餐订单、号卡订单,并支持混合支付方式(钱包 + 在线支付)。
修改说明:
- 增加
wallet_payment_amount字段:钱包支付金额 - 增加
online_payment_amount字段:在线支付金额 - 支持用户在购买套餐时选择支付方式(全部钱包支付、全部在线支付、混合支付)
实体字段(只列出新增字段):
wallet_payment_amount:钱包支付金额(BIGINT,单位:分,默认 0)【新增】online_payment_amount:在线支付金额(BIGINT,单位:分,默认 0)【新增】
支付规则:
wallet_payment_amount+online_payment_amount=amount(订单总金额)- 当
payment_method为 "wallet" 时,wallet_payment_amount=amount,online_payment_amount= 0 - 当
payment_method为 "online" 时,online_payment_amount=amount,wallet_payment_amount= 0 - 混合支付时,
payment_method为 "mixed",两个字段都 > 0
Scenario: 全额钱包支付
- WHEN 用户购买套餐,订单金额为 30 00 分(30 元),选择钱包支付,钱包余额为 10000 分
- THEN 系统创建订单,
amount为 3000,payment_method为 "wallet",wallet_payment_amount为 3000,online_payment_amount为 0
Scenario: 全额在线支付
- WHEN 用户购买套餐,订单金额为 3000 分(30 元),选择在线支付
- THEN 系统创建订单,
amount为 3000,payment_method为 "online",wallet_payment_amount为 0,online_payment_amount为 3000
Scenario: 混合支付
- WHEN 用户购买套餐,订单金额为 5000 分(50 元),钱包余额为 3000 分,用户选择钱包支付 3000 分 + 在线支付 2000 分
- THEN 系统创建订单,
amount为 5000,payment_method为 "mixed",wallet_payment_amount为 3000,online_payment_amount为 2000
Scenario: 钱包余额不足,部分钱包支付
- WHEN 用户购买套餐,订单金额为 5000 分(50 元),钱包余额为 2000 分,用户选择钱包支付 2000 分 + 在线支付 3000 分
- THEN 系统先冻结钱包余额 2000 分,创建订单,
wallet_payment_amount为 2000,online_payment_amount为 3000,等待用户完成在线支付
Scenario: 钱包余额不足,无法全额钱包支付
- WHEN 用户购买套餐,订单金额为 5000 分(50 元),钱包余额为 3000 分,用户选择钱包支付
- THEN 系统拒绝创建订单,返回错误信息"钱包余额不足",建议用户选择混合支付或在线支付
Requirement: 订单状态流转
系统 SHALL 管理订单的状态流转,确保状态变更符合业务规则。
状态定义:
- 1-待支付: 订单已创建,等待用户支付
- 2-已支付: 用户已支付,等待系统处理
- 3-已完成: 订单已完成(激活/发货等)
- 4-已取消: 订单已取消
- 5-已退款: 订单已退款
状态流转规则:
- 待支付(1) → 已支付(2): 用户完成支付
- 待支付(1) → 已取消(4): 用户取消订单或订单超时
- 已支付(2) → 已完成(3): 系统完成订单处理(激活/发货)
- 已支付(2) → 已退款(5): 用户申请退款且审核通过
- 已完成(3) → 已退款(5): 用户申请退款且审核通过(特殊情况)
Scenario: 用户支付订单
- WHEN 用户支付待支付订单(ID 为 10001),支付金额为 30.00 元
- THEN 系统将订单状态从 1(待支付) 变更为 2(已支付),
paid_at记录支付时间
Scenario: 单卡套餐订单完成
- WHEN 系统处理完单卡套餐订单(ID 为 10001),激活 IoT 卡并分配套餐
- THEN 系统将订单状态从 2(已支付) 变更为 3(已完成),
completed_at记录完成时间
Scenario: 设备级套餐订单完成
- WHEN 系统处理完设备级套餐订单(ID 为 10002),为设备绑定的所有 IoT 卡分配套餐
- THEN 系统将订单状态从 2(已支付) 变更为 3(已完成),
completed_at记录完成时间
Requirement: 订单支付方式
系统 SHALL 支持三种支付方式:钱包支付、在线支付、运营商直付。
支付方式:
- 钱包支付(wallet): 从用户钱包余额扣款
- 在线支付(online): 通过第三方支付(微信/支付宝等)
- 运营商直付(carrier): 用户直接支付给运营商(仅号卡订单)
支付规则:
- 一次性分佣订单必须使用钱包支付
- 套餐购买订单可以使用钱包或在线支付
- 号卡订单必须使用运营商直付
Scenario: 钱包支付订单
- WHEN 用户使用钱包支付订单(金额为 30.00 元),钱包余额为 50.00 元
- THEN 系统从钱包扣除 30.00 元,订单状态变更为 2(已支付),
payment_method为 "wallet"
Scenario: 钱包余额不足
- WHEN 用户使用钱包支付订单(金额为 30.00 元),钱包余额为 20.00 元
- THEN 系统拒绝支付,返回错误信息"钱包余额不足"
Scenario: 一次性分佣订单强制钱包支付
- WHEN 用户购买配置了一次性分佣的套餐,尝试使用在线支付
- THEN 系统拒绝支付,返回错误信息"一次性分佣订单必须使用钱包支付"
Requirement: 订单分佣触发
系统 SHALL 在订单完成时触发分佣计算,根据代理分佣规则创建分佣记录。
触发条件:
- 订单状态变更为 3(已完成)
- 订单有
agent_id(通过代理销售) - 代理配置了分佣规则
分佣计算规则:
- 单卡套餐订单: 根据 IoT 卡关联的代理分佣规则计算分佣
- 设备级套餐订单: 分佣只计算一次(不按设备绑定的 IoT 卡数量倍增)
- 号卡订单: 下单即冻结分佣,次月通过 Excel 导入解冻
Scenario: 单卡套餐购买订单触发分佣
- WHEN 代理(ID 为 123)的单卡套餐订单(ID 为 10001)完成,订单金额为 30.00 元,代理配置了 5.00 元一次性分佣
- THEN 系统创建分佣记录,
agent_id为 123,order_id为 10001,amount为 5.00,状态为 1(冻结)
Scenario: 设备级套餐订单触发分佣(只计算一次)
- WHEN 代理(ID 为 123)的设备级套餐订单(ID 为 10002)完成,设备绑定 3 张 IoT 卡,订单金额为 399.00 元,代理配置了 100.00 元长期分佣
- THEN 系统创建一条分佣记录,
agent_id为 123,order_id为 10002,amount为 100.00,状态为 1(冻结),不是 3 × 100.00
Scenario: 号卡订单触发分佣
- WHEN 代理(ID 为 123)的号卡订单(ID 为 10003)创建,订单金额为 30.00 元,代理配置了长期分佣
- THEN 系统创建分佣记录,
agent_id为 123,order_id为 10003,状态为 1(冻结),等待次月通过 Excel 导入解冻
Requirement: 订单查询和筛选
系统 SHALL 支持多维度查询和筛选订单。
查询条件:
- 订单编号(精确匹配)
- 订单类型(1-套餐订单 2-号卡订单)
- 订单状态(单选或多选)
- IoT 卡 ID(精确匹配)
- 设备 ID(精确匹配)
- 号卡 ID(精确匹配)
- 用户 ID(精确匹配)
- 代理 ID(精确匹配)
- 支付方式(单选或多选)
- 创建时间范围(开始时间 - 结束时间)
- 支付时间范围(开始时间 - 结束时间)
- 完成时间范围(开始时间 - 结束时间)
分页:
- 默认每页 20 条,最大每页 100 条
- 返回总记录数和总页数
Scenario: 查询用户的所有订单
- WHEN 用户(ID 为 2001)查询自己的所有订单
- THEN 系统返回
user_id为 2001 的所有订单列表,按创建时间倒序排列
Scenario: 查询代理的订单
- WHEN 代理(ID 为 123)查询自己的订单,筛选已完成的套餐订单
- THEN 系统返回
agent_id为 123 且order_type为 1 且status为 3(已完成) 的订单列表
Scenario: 查询 IoT 卡的订单历史
- WHEN 运营人员查询 IoT 卡(ID 为 1001)的所有订单
- THEN 系统返回
iot_card_id为 1001 的所有订单列表,包含套餐购买记录
Scenario: 查询设备的订单历史
- WHEN 运营人员查询设备(ID 为 5001)的所有订单
- THEN 系统返回
device_id为 5001 的所有设备级套餐订单列表
Requirement: 订单数据校验
系统 SHALL 对订单数据进行校验,确保数据完整性和一致性,特别是支付金额的一致性。
新增校验规则:
wallet_payment_amount:必填,≥ 0,最多精确到分online_payment_amount:必填,≥ 0,最多精确到分wallet_payment_amount+online_payment_amount=amount(订单总金额)- 当
payment_method为 "wallet" 时,wallet_payment_amount必须 =amount - 当
payment_method为 "online" 时,online_payment_amount必须 =amount - 当
payment_method为 "mixed" 时,两个字段都必须 > 0
Scenario: 支付金额不一致
- WHEN 创建订单,
amount为 5000,wallet_payment_amount为 2000,online_payment_amount为 2000 - THEN 系统拒绝创建,返回错误信息"支付金额总和与订单金额不一致"
Scenario: 钱包支付时在线支付金额不为 0
- WHEN 创建订单,
payment_method为 "wallet",wallet_payment_amount为 3000,online_payment_amount为 0(正确),但用户错误地设置online_payment_amount为 100 - THEN 系统拒绝创建,返回错误信息"钱包支付时在线支付金额必须为 0"
Scenario: 混合支付时钱包支付金额为 0
- WHEN 创建订单,
payment_method为 "mixed",wallet_payment_amount为 0,online_payment_amount为 5000 - THEN 系统拒绝创建,返回错误信息"混合支付时钱包支付金额和在线支付金额都必须大于 0"
Requirement: 订单支付处理
系统 SHALL 根据支付方式正确处理订单支付,包括钱包扣款、在线支付、混合支付等。
钱包支付流程:
- 检查钱包可用余额是否充足
- 冻结钱包余额(
frozen_balance增加) - 创建订单,状态为"待支付"
- 订单完成后,扣减钱包余额(
balance减少,frozen_balance减少),创建钱包明细记录 - 订单取消时,解冻钱包余额(
frozen_balance减少)
在线支付流程:
- 创建订单,状态为"待支付"
- 调用第三方支付接口
- 用户完成支付后,订单状态变更为"已支付"
- 订单完成后,订单状态变更为"已完成"
混合支付流程:
- 检查钱包可用余额是否充足(钱包支付部分)
- 冻结钱包余额
- 创建订单,状态为"待支付"
- 调用第三方支付接口(在线支付部分)
- 用户完成在线支付后,扣减钱包余额,订单状态变更为"已支付"
- 订单完成后,订单状态变更为"已完成"
Scenario: 钱包支付订单完成
- WHEN 用户使用钱包支付购买套餐,订单金额为 3000 分
- THEN 系统:
- 创建订单,状态为"待支付",冻结钱包余额 3000 分
- 订单处理完成后,扣减钱包余额 3000 分,解冻 3000 分,创建钱包明细记录(类型为"扣款"),订单状态变更为"已完成"
Scenario: 混合支付订单完成
- WHEN 用户使用混合支付购买套餐,钱包支付 2000 分 + 在线支付 3000 分
- THEN 系统:
- 创建订单,状态为"待支付",冻结钱包余额 2000 分
- 用户完成在线支付 3000 分后,扣减钱包余额 2000 分,解冻 2000 分,创建钱包明细记录,订单状态变更为"已支付"
- 订单处理完成后,订单状态变更为"已完成"
Scenario: 订单取消,解冻钱包余额
- WHEN 用户使用钱包支付创建订单,订单金额为 3000 分,然后取消订单
- THEN 系统解冻钱包余额 3000 分(
frozen_balance减少 3000),订单状态变更为"已取消"