feat: 客户端接口数据模型基础准备
- 新增资产状态、订单来源、操作人类型、实名链接类型常量 - 8个模型新增字段(asset_status/generation/source/retail_price等) - 数据库迁移000082:7张表15+字段,含存量retail_price回填 - BUG-1修复:代理零售价渠道隔离,cost_price分配锁定 - BUG-2修复:一次性佣金仅客户端订单触发 - BUG-4修复:充值回调Store操作纳入事务 - 新增资产手动停用接口(PATCH /iot-cards/:id/deactivate、/devices/:id/deactivate) - Carrier管理新增实名链接配置 - 后台订单generation写时快照 - BatchUpdatePricing支持retail_price调价目标 - 清理全部H5旧接口和个人客户旧登录方法
This commit is contained in:
88
internal/service/asset/lifecycle_service.go
Normal file
88
internal/service/asset/lifecycle_service.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package asset
|
||||
|
||||
import (
|
||||
"context"
|
||||
stderrors "errors"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var deactivatableAssetStatuses = []int{constants.AssetStatusInStock, constants.AssetStatusSold}
|
||||
|
||||
// LifecycleService 资产生命周期服务
|
||||
type LifecycleService struct {
|
||||
db *gorm.DB
|
||||
iotCardStore *postgres.IotCardStore
|
||||
deviceStore *postgres.DeviceStore
|
||||
}
|
||||
|
||||
// NewLifecycleService 创建资产生命周期服务
|
||||
func NewLifecycleService(db *gorm.DB, iotCardStore *postgres.IotCardStore, deviceStore *postgres.DeviceStore) *LifecycleService {
|
||||
return &LifecycleService{
|
||||
db: db,
|
||||
iotCardStore: iotCardStore,
|
||||
deviceStore: deviceStore,
|
||||
}
|
||||
}
|
||||
|
||||
// DeactivateIotCard 手动停用 IoT 卡
|
||||
func (s *LifecycleService) DeactivateIotCard(ctx context.Context, id uint) error {
|
||||
card, err := s.iotCardStore.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
if stderrors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return errors.New(errors.CodeIotCardNotFound)
|
||||
}
|
||||
return errors.Wrap(errors.CodeDatabaseError, err, "查询IoT卡失败")
|
||||
}
|
||||
|
||||
if !canDeactivateAsset(card.AssetStatus) {
|
||||
return errors.New(errors.CodeForbidden, "当前状态不允许停用")
|
||||
}
|
||||
|
||||
result := s.db.WithContext(ctx).Model(&model.IotCard{}).
|
||||
Where("id = ? AND asset_status IN ?", id, deactivatableAssetStatuses).
|
||||
Update("asset_status", constants.AssetStatusDeactivated)
|
||||
if result.Error != nil {
|
||||
return errors.Wrap(errors.CodeDatabaseError, result.Error, "停用IoT卡失败")
|
||||
}
|
||||
if result.RowsAffected == 0 {
|
||||
return errors.New(errors.CodeConflict, "状态已变更,请刷新后重试")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeactivateDevice 手动停用设备
|
||||
func (s *LifecycleService) DeactivateDevice(ctx context.Context, id uint) error {
|
||||
device, err := s.deviceStore.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
if stderrors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return errors.New(errors.CodeNotFound, "设备不存在")
|
||||
}
|
||||
return errors.Wrap(errors.CodeDatabaseError, err, "查询设备失败")
|
||||
}
|
||||
|
||||
if !canDeactivateAsset(device.AssetStatus) {
|
||||
return errors.New(errors.CodeForbidden, "当前状态不允许停用")
|
||||
}
|
||||
|
||||
result := s.db.WithContext(ctx).Model(&model.Device{}).
|
||||
Where("id = ? AND asset_status IN ?", id, deactivatableAssetStatuses).
|
||||
Update("asset_status", constants.AssetStatusDeactivated)
|
||||
if result.Error != nil {
|
||||
return errors.Wrap(errors.CodeDatabaseError, result.Error, "停用设备失败")
|
||||
}
|
||||
if result.RowsAffected == 0 {
|
||||
return errors.New(errors.CodeConflict, "状态已变更,请刷新后重试")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func canDeactivateAsset(assetStatus int) bool {
|
||||
return assetStatus == constants.AssetStatusInStock || assetStatus == constants.AssetStatusSold
|
||||
}
|
||||
Reference in New Issue
Block a user