package system import ( "fmt" "gorm.io/gorm" ) // The migration resolves historical IDs once. Runtime role assignment uses // business_level and is independent of editable names and migration helpers. func migrateBusinessRoles(db *gorm.DB) error { if !db.Migrator().HasColumn(&authorityPO{}, "BusinessLevel") { if err := db.Migrator().AddColumn(&authorityPO{}, "BusinessLevel"); err != nil { return err } } var roles []authorityPO if err := db.Find(&roles).Error; err != nil { return err } if len(roles) == 0 { return ensureBusinessRoleIndex(db) } legacy := map[int]string{1: "2083497078545207297", 2: "2087435436573081601", 3: "2087361690139152385"} names := map[int]string{1: "一级商务", 2: "二级商务", 3: "三级商务"} hasMap := db.Migrator().HasTable("sw_kra_id_map") applicable := hasMap for _, role := range roles { if role.BusinessLevel != nil { applicable = true } for _, name := range names { if role.AuthorityName == name { applicable = true } } } if !applicable { return ensureBusinessRoleIndex(db) } bindings := map[int]uint{} for _, role := range roles { if role.BusinessLevel == nil { continue } level := *role.BusinessLevel if level < 1 || level > 3 || role.AuthorityID == 888 || bindings[level] != 0 { return fmt.Errorf("invalid or duplicate business role level %d", level) } bindings[level] = role.AuthorityID } for level := 1; level <= 3; level++ { if bindings[level] != 0 { continue } var ids []uint if hasMap { if err := db.Table("sw_kra_id_map m").Select("m.new_id").Joins("JOIN sys_authorities a ON a.authority_id=m.new_id AND a.deleted_at IS NULL").Where("m.entity='role' AND m.old_id=? AND m.new_id<>888", legacy[level]).Scan(&ids).Error; err != nil { return err } } else { for _, role := range roles { if role.AuthorityID != 888 && role.AuthorityName == names[level] { ids = append(ids, role.AuthorityID) } } } if len(ids) != 1 { // A generic first installation can have only the administrator. // Migrated SW databases must supply all three mapped roles. if !hasMap && len(bindings) == 0 && len(roles) == 1 && roles[0].AuthorityID == 888 { return ensureBusinessRoleIndex(db) } return fmt.Errorf("business level %d requires exactly one migration role", level) } for _, id := range bindings { if id == ids[0] { return fmt.Errorf("one role cannot represent multiple business levels") } } bindings[level] = ids[0] } if err := db.Transaction(func(tx *gorm.DB) error { for level, id := range bindings { if err := tx.Model(&authorityPO{}).Where("authority_id=?", id).UpdateColumn("business_level", level).Error; err != nil { return err } } return nil }); err != nil { return err } return ensureBusinessRoleIndex(db) } func ensureBusinessRoleIndex(db *gorm.DB) error { const name = "uk_authority_business_level" if db.Migrator().HasIndex(&authorityPO{}, name) { return nil } return db.Migrator().CreateIndex(&authorityPO{}, name) } func CheckBusinessRoles(db *gorm.DB) error { var roles []authorityPO if err := db.Where("business_level IS NOT NULL").Find(&roles).Error; err != nil { return err } seen := map[int]bool{} for _, role := range roles { if *role.BusinessLevel < 1 || *role.BusinessLevel > 3 || role.AuthorityID == 888 || seen[*role.BusinessLevel] { return fmt.Errorf("invalid business role binding") } seen[*role.BusinessLevel] = true } if len(seen) != 3 { return fmt.Errorf("three business role bindings are required") } return nil }