重构: 将卡/设备的套餐系列绑定从分配ID改为系列ID

- 数据库: 重命名 series_allocation_id → series_id
- Model: IotCard 和 Device 字段重命名
- DTO: 所有请求/响应字段统一为 series_id
- Store: 方法重命名,新增 GetByShopAndSeries 查询
- Service: 业务逻辑优化,系列验证和权限验证分离
- 测试: 更新所有测试用例,新增 shop_series_allocation_store_test.go
- 文档: 更新 API 文档说明参数变更

BREAKING CHANGE: API 参数从 series_allocation_id 改为 series_id
This commit is contained in:
2026-02-02 12:09:53 +08:00
parent a30b3036bb
commit 37f43d2e2d
27 changed files with 673 additions and 301 deletions

View File

@@ -3,18 +3,18 @@ package dto
import "time"
type ListDeviceRequest struct {
Page int `json:"page" query:"page" validate:"omitempty,min=1" minimum:"1" description:"页码"`
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100" minimum:"1" maximum:"100" description:"每页数量"`
DeviceNo string `json:"device_no" query:"device_no" validate:"omitempty,max=100" maxLength:"100" description:"设备号(模糊查询)"`
DeviceName string `json:"device_name" query:"device_name" validate:"omitempty,max=255" maxLength:"255" description:"设备名称(模糊查询)"`
Status *int `json:"status" query:"status" validate:"omitempty,min=1,max=4" minimum:"1" maximum:"4" description:"状态 (1:在库, 2:已分销, 3:已激活, 4:已停用)"`
ShopID *uint `json:"shop_id" query:"shop_id" description:"店铺ID (NULL表示平台库存)"`
SeriesAllocationID *uint `json:"series_allocation_id" query:"series_allocation_id" description:"套餐系列分配ID"`
BatchNo string `json:"batch_no" query:"batch_no" validate:"omitempty,max=100" maxLength:"100" description:"批次号"`
DeviceType string `json:"device_type" query:"device_type" validate:"omitempty,max=50" maxLength:"50" description:"设备类型"`
Manufacturer string `json:"manufacturer" query:"manufacturer" validate:"omitempty,max=255" maxLength:"255" description:"制造商(模糊查询)"`
CreatedAtStart *time.Time `json:"created_at_start" query:"created_at_start" description:"创建时间起始"`
CreatedAtEnd *time.Time `json:"created_at_end" query:"created_at_end" description:"创建时间结束"`
Page int `json:"page" query:"page" validate:"omitempty,min=1" minimum:"1" description:"页码"`
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100" minimum:"1" maximum:"100" description:"每页数量"`
DeviceNo string `json:"device_no" query:"device_no" validate:"omitempty,max=100" maxLength:"100" description:"设备号(模糊查询)"`
DeviceName string `json:"device_name" query:"device_name" validate:"omitempty,max=255" maxLength:"255" description:"设备名称(模糊查询)"`
Status *int `json:"status" query:"status" validate:"omitempty,min=1,max=4" minimum:"1" maximum:"4" description:"状态 (1:在库, 2:已分销, 3:已激活, 4:已停用)"`
ShopID *uint `json:"shop_id" query:"shop_id" description:"店铺ID (NULL表示平台库存)"`
SeriesID *uint `json:"series_id" query:"series_id" description:"套餐系列ID"`
BatchNo string `json:"batch_no" query:"batch_no" validate:"omitempty,max=100" maxLength:"100" description:"批次号"`
DeviceType string `json:"device_type" query:"device_type" validate:"omitempty,max=50" maxLength:"50" description:"设备类型"`
Manufacturer string `json:"manufacturer" query:"manufacturer" validate:"omitempty,max=255" maxLength:"255" description:"制造商(模糊查询)"`
CreatedAtStart *time.Time `json:"created_at_start" query:"created_at_start" description:"创建时间起始"`
CreatedAtEnd *time.Time `json:"created_at_end" query:"created_at_end" description:"创建时间结束"`
}
type DeviceResponse struct {
@@ -31,7 +31,7 @@ type DeviceResponse struct {
Status int `json:"status" description:"状态 (1:在库, 2:已分销, 3:已激活, 4:已停用)"`
StatusName string `json:"status_name" description:"状态名称"`
BoundCardCount int `json:"bound_card_count" description:"已绑定卡数量"`
SeriesAllocationID *uint `json:"series_allocation_id,omitempty" description:"套餐系列分配ID"`
SeriesID *uint `json:"series_id,omitempty" description:"套餐系列ID"`
FirstCommissionPaid bool `json:"first_commission_paid" description:"一次性佣金是否已发放"`
AccumulatedRecharge int64 `json:"accumulated_recharge" description:"累计充值金额(分)"`
ActivatedAt *time.Time `json:"activated_at,omitempty" description:"激活时间"`
@@ -129,8 +129,8 @@ type RecallDevicesResponse struct {
// BatchSetDeviceSeriesBindngRequest 批量设置设备的套餐系列绑定请求
type BatchSetDeviceSeriesBindngRequest struct {
DeviceIDs []uint `json:"device_ids" validate:"required,min=1,max=500,dive,required" required:"true" minItems:"1" maxItems:"500" description:"设备ID列表"`
SeriesAllocationID uint `json:"series_allocation_id" validate:"required,min=0" required:"true" minimum:"0" description:"套餐系列分配ID0表示清除关联"`
DeviceIDs []uint `json:"device_ids" validate:"required,min=1,max=500,dive,required" required:"true" minItems:"1" maxItems:"500" description:"设备ID列表"`
SeriesID uint `json:"series_id" validate:"required,min=0" required:"true" minimum:"0" description:"套餐系列ID0表示清除关联"`
}
// DeviceSeriesBindngFailedItem 设备系列绑定失败项

View File

@@ -3,20 +3,20 @@ package dto
import "time"
type ListStandaloneIotCardRequest struct {
Page int `json:"page" query:"page" validate:"omitempty,min=1" minimum:"1" description:"页码"`
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100" minimum:"1" maximum:"100" description:"每页数量"`
Status *int `json:"status" query:"status" validate:"omitempty,min=1,max=4" minimum:"1" maximum:"4" description:"状态 (1:在库, 2:已分销, 3:已激活, 4:已停用)"`
CarrierID *uint `json:"carrier_id" query:"carrier_id" description:"运营商ID"`
ShopID *uint `json:"shop_id" query:"shop_id" description:"分销商ID"`
SeriesAllocationID *uint `json:"series_allocation_id" query:"series_allocation_id" description:"套餐系列分配ID"`
ICCID string `json:"iccid" query:"iccid" validate:"omitempty,max=20" maxLength:"20" description:"ICCID(模糊查询)"`
MSISDN string `json:"msisdn" query:"msisdn" validate:"omitempty,max=20" maxLength:"20" description:"卡接入号(模糊查询)"`
BatchNo string `json:"batch_no" query:"batch_no" validate:"omitempty,max=100" maxLength:"100" description:"批次号"`
PackageID *uint `json:"package_id" query:"package_id" description:"套餐ID"`
IsDistributed *bool `json:"is_distributed" query:"is_distributed" description:"是否已分销 (true:已分销, false:未分销)"`
IsReplaced *bool `json:"is_replaced" query:"is_replaced" description:"是否有换卡记录 (true:有换卡记录, false:无换卡记录)"`
ICCIDStart string `json:"iccid_start" query:"iccid_start" validate:"omitempty,max=20" maxLength:"20" description:"ICCID起始号"`
ICCIDEnd string `json:"iccid_end" query:"iccid_end" validate:"omitempty,max=20" maxLength:"20" description:"ICCID结束号"`
Page int `json:"page" query:"page" validate:"omitempty,min=1" minimum:"1" description:"页码"`
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100" minimum:"1" maximum:"100" description:"每页数量"`
Status *int `json:"status" query:"status" validate:"omitempty,min=1,max=4" minimum:"1" maximum:"4" description:"状态 (1:在库, 2:已分销, 3:已激活, 4:已停用)"`
CarrierID *uint `json:"carrier_id" query:"carrier_id" description:"运营商ID"`
ShopID *uint `json:"shop_id" query:"shop_id" description:"分销商ID"`
SeriesID *uint `json:"series_id" query:"series_id" description:"套餐系列ID"`
ICCID string `json:"iccid" query:"iccid" validate:"omitempty,max=20" maxLength:"20" description:"ICCID(模糊查询)"`
MSISDN string `json:"msisdn" query:"msisdn" validate:"omitempty,max=20" maxLength:"20" description:"卡接入号(模糊查询)"`
BatchNo string `json:"batch_no" query:"batch_no" validate:"omitempty,max=100" maxLength:"100" description:"批次号"`
PackageID *uint `json:"package_id" query:"package_id" description:"套餐ID"`
IsDistributed *bool `json:"is_distributed" query:"is_distributed" description:"是否已分销 (true:已分销, false:未分销)"`
IsReplaced *bool `json:"is_replaced" query:"is_replaced" description:"是否有换卡记录 (true:有换卡记录, false:无换卡记录)"`
ICCIDStart string `json:"iccid_start" query:"iccid_start" validate:"omitempty,max=20" maxLength:"20" description:"ICCID起始号"`
ICCIDEnd string `json:"iccid_end" query:"iccid_end" validate:"omitempty,max=20" maxLength:"20" description:"ICCID结束号"`
}
type StandaloneIotCardResponse struct {
@@ -41,7 +41,7 @@ type StandaloneIotCardResponse struct {
RealNameStatus int `json:"real_name_status" description:"实名状态 (0:未实名, 1:已实名)"`
NetworkStatus int `json:"network_status" description:"网络状态 (0:停机, 1:开机)"`
DataUsageMB int64 `json:"data_usage_mb" description:"累计流量使用(MB)"`
SeriesAllocationID *uint `json:"series_allocation_id,omitempty" description:"套餐系列分配ID"`
SeriesID *uint `json:"series_id,omitempty" description:"套餐系列ID"`
FirstCommissionPaid bool `json:"first_commission_paid" description:"一次性佣金是否已发放"`
AccumulatedRecharge int64 `json:"accumulated_recharge" description:"累计充值金额(分)"`
CreatedAt time.Time `json:"created_at" description:"创建时间"`
@@ -133,8 +133,8 @@ type IotCardDetailResponse struct {
// BatchSetCardSeriesBindngRequest 批量设置卡的套餐系列绑定请求
type BatchSetCardSeriesBindngRequest struct {
ICCIDs []string `json:"iccids" validate:"required,min=1,max=500,dive,required" required:"true" minItems:"1" maxItems:"500" description:"ICCID列表"`
SeriesAllocationID uint `json:"series_allocation_id" validate:"required,min=0" required:"true" minimum:"0" description:"套餐系列分配ID0表示清除关联"`
ICCIDs []string `json:"iccids" validate:"required,min=1,max=500,dive,required" required:"true" minItems:"1" maxItems:"500" description:"ICCID列表"`
SeriesID uint `json:"series_id" validate:"required,min=0" required:"true" minimum:"0" description:"套餐系列ID0表示清除关联"`
}
// CardSeriesBindngFailedItem 卡系列绑定失败项