Files
junhong_cmp_fiber/docs/7月迭代/需求05-套餐分配生效条件.md
2026-07-13 12:01:18 +09:00

4.8 KiB
Raw Blame History

需求05套餐分配生效条件ExpiryBase 覆盖)


背景

Package.ExpiryBase 已存在(from_activation / from_purchase),在套餐创建时设定,控制套餐何时开始计时。

需求:分配套餐给代理时,可以对单条分配记录二次覆盖这个值。


快照链设计

ShopPackageAllocation.expiry_base_override分配时设置覆盖值
        ↓ 订单创建时读取取有效值override 优先,否则用套餐默认)
PackageUsage.expiry_base_snapshot快照进去
        ↓ 激活时读取
activation_service 读 usage.ExpiryBaseSnapshot不再直接读 pkg.ExpiryBase

遗留数据兜底:ExpiryBaseSnapshot 为空(旧数据)时,回退读 pkg.ExpiryBase,行为不变。


数据库变更

1. ShopPackageAllocation 新增覆盖字段

ALTER TABLE tb_shop_package_allocation
    ADD COLUMN expiry_base_override VARCHAR(30) DEFAULT NULL
        COMMENT '生效条件覆盖NULL=使用套餐默认值, from_activation=实名即生效, from_purchase=购买即生效)';

2. PackageUsage 新增快照字段

ALTER TABLE tb_package_usage
    ADD COLUMN expiry_base_snapshot VARCHAR(30) NOT NULL DEFAULT ''
        COMMENT '生效条件快照(创建时从分配记录取有效值写入,空字符串=旧数据兜底读套餐原值)';

旧数据不回填,默认空字符串,激活时自动兜底。


Model 变更

ShopPackageAllocationinternal/model/shop_package_allocation.go

// ExpiryBaseOverride 生效条件覆盖
// NULL = 使用宿主套餐的 ExpiryBase有值 = 分配时指定,不受套餐后续修改影响
ExpiryBaseOverride *string `gorm:"column:expiry_base_override;type:varchar(30);comment:生效条件覆盖 NULL=使用套餐默认 from_activation=实名即生效 from_purchase=购买即生效" json:"expiry_base_override"`

PackageUsageinternal/model/package.go

// ExpiryBaseSnapshot 生效条件快照(创建订单时写入,空字符串=旧数据兜底读套餐原值)
ExpiryBaseSnapshot string `gorm:"column:expiry_base_snapshot;type:varchar(30);not null;default:'';comment:生效条件快照 创建时从分配记录取有效值" json:"expiry_base_snapshot"`

业务逻辑变更

1. 订单创建时快照(internal/service/order/service.go

订单创建已通过 GetByShopAndPackage 查询分配记录(现有逻辑),在此基础上追加:

// 取生效条件有效值:分配覆盖 > 套餐默认
expiryBase := pkg.ExpiryBase
if allocation.ExpiryBaseOverride != nil && *allocation.ExpiryBaseOverride != "" {
    expiryBase = *allocation.ExpiryBaseOverride
}
// 创建 PackageUsage 时写入快照
usage.ExpiryBaseSnapshot = expiryBase

2. 激活时读快照(internal/service/package/activation_service.go

// 修改前:直接读套餐原值
expiryBase := pkg.ExpiryBase

// 修改后:优先读快照,旧数据兜底
expiryBase := pkg.ExpiryBase // 兜底(旧数据 ExpiryBaseSnapshot 为空)
if usage.ExpiryBaseSnapshot != "" {
    expiryBase = usage.ExpiryBaseSnapshot
}

同文件另一处(activation_service.go:556)同理修改。

internal/service/order/service.go:2290 中后台囤货路径的 ExpiryBase 判断也需同样改为读快照(兜底逻辑一致)。


API 变更

1. 分配套餐接口(新增参数)

POST /admin/shop-package-allocations

请求 DTO 新增字段:

ExpiryBaseOverride *string `json:"expiry_base_override" validate:"omitempty,oneof=from_activation from_purchase" description:"生效条件覆盖(不传=使用套餐默认, from_activation=实名即生效, from_purchase=购买即生效)"`

2. 修改已分配套餐的生效条件(新接口)

PATCH /admin/shop-package-allocations/{id}/expiry-base

请求 DTO

type UpdateAllocationExpiryBaseRequest struct {
    ExpiryBaseOverride *string `json:"expiry_base_override" validate:"omitempty,oneof=from_activation from_purchase" description:"生效条件null=恢复套餐默认, from_activation=实名即生效, from_purchase=购买即生效)"`
}

注意:修改已有分配记录的覆盖值,不影响已创建的 PackageUsage快照已定只影响后续新建的订单。


前端对接

套餐分配弹框

新增"生效条件"选择项:

生效条件:
  ○ 跟随套餐默认(默认选中,不传 expiry_base_override
  ○ 购买即生效from_purchase
  ○ 实名即生效from_activation

已分配套餐列表

列表新增"生效条件"列:

展示
NULL 套餐默认
from_activation 实名即生效(已覆盖)
from_purchase 购买即生效(已覆盖)

操作列增加"修改生效条件"按钮,调用 PATCH /admin/shop-package-allocations/{id}/expiry-base