package business import ( "context" "encoding/json" "errors" "sync" "time" "gorm.io/gorm" "gorm.io/gorm/clause" "kra/internal/biz/business" ) const otherSettingsKey = "sw.channel_effectiveness" // Projection of the existing parameter-management table; no new settings table. type otherSettingsPO struct { ID uint `gorm:"primaryKey"` CreatedAt, UpdatedAt time.Time DeletedAt gorm.DeletedAt Name, Key, Value, Desc string } func (otherSettingsPO) TableName() string { return "sys_params" } type effectivenessJSON struct { Amount *int64 `json:"amount"` Days *int64 `json:"days"` } func newOtherSettings(value business.OtherSettings) otherSettingsPO { encoded, _ := json.Marshal(effectivenessJSON{Amount: &value.Amount, Days: &value.Days}) return otherSettingsPO{Name: "渠道有效端判定", Key: otherSettingsKey, Value: string(encoded), Desc: "其他设置:达标金额(元)和判定窗口(天)"} } func toBizOtherSettings(po otherSettingsPO) (*business.OtherSettings, error) { var value effectivenessJSON if err := json.Unmarshal([]byte(po.Value), &value); err != nil || value.Amount == nil || value.Days == nil { return nil, business.ErrOtherSettingsStored } result := &business.OtherSettings{Amount: *value.Amount, Days: *value.Days, UpdatedAt: po.UpdatedAt} if err := business.ValidateOtherSettings(*result); err != nil { return nil, business.ErrOtherSettingsStored } return result, nil } type otherSettingsRepo struct { data Provider // Serialize first creation as sys_params has no unique index on key. mu sync.Mutex } func NewOtherSettingsRepo(data Provider) business.OtherSettingsRepo { return &otherSettingsRepo{data: data} } func (r *otherSettingsRepo) Find(ctx context.Context) (*business.OtherSettings, error) { var po otherSettingsPO err := r.data.DB().WithContext(ctx).Where(map[string]any{"key": otherSettingsKey}).First(&po).Error if errors.Is(err, gorm.ErrRecordNotFound) { return nil, nil } if err != nil { return nil, business.ErrStorage } return toBizOtherSettings(po) } func (r *otherSettingsRepo) Save(ctx context.Context, value business.OtherSettings) (*business.OtherSettings, error) { r.mu.Lock() defer r.mu.Unlock() po := newOtherSettings(value) err := r.data.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error { var existing otherSettingsPO err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where(map[string]any{"key": otherSettingsKey}).First(&existing).Error if errors.Is(err, gorm.ErrRecordNotFound) { return tx.Create(&po).Error } if err != nil { return err } po.ID, po.CreatedAt, po.UpdatedAt = existing.ID, existing.CreatedAt, time.Now() return tx.Model(&existing).Updates(map[string]any{"value": po.Value, "updated_at": po.UpdatedAt}).Error }) if err != nil { return nil, business.ErrStorage } return toBizOtherSettings(po) }