diff --git a/main.go b/main.go index d900ead..ab4409e 100755 --- a/main.go +++ b/main.go @@ -43,8 +43,10 @@ func main() { // Ejecutar migraciones migrations.Migrate() } else { - // Crear/actualizar tablas de Renovaciones (idempotente) + // Crear/actualizar tablas de Renovaciones e idempotente) migrations.MigrateRenovaciones() + // Crear/actualizar tablas de Portal, Telegram y Proyectos + migrations.MigratePortal() // Crear tablas de integraciones y pasarelas si no existen app.Http.Database.DB.AutoMigrate( &models.QueryHistory{}, diff --git a/migrations/migrate.go b/migrations/migrate.go index 5a2d8ae..a277e54 100755 --- a/migrations/migrate.go +++ b/migrations/migrate.go @@ -277,6 +277,31 @@ func SeedPlantillasBase() { log.Println("[SEED] SeedPlantillasBase completado.") } +// MigratePortal crea/actualiza las tablas del módulo Portal de Clientes, Proyectos, +// Facturas y Telegram. Es idempotente. +func MigratePortal() { + db := app.Http.Database.DB + if err := db.AutoMigrate( + &models.Roles{}, // agrega columnas es_portal_cliente / es_portal_partner si no existen + &models.TelegramConfig{}, + &models.TelegramLog{}, + &models.ClienteDocumento{}, + &models.PortalUser{}, + &models.PortalAcceso{}, + &models.Proyecto{}, + &models.ProyectoFase{}, + &models.ProyectoAvance{}, + &models.ProyectoEntregable{}, + &models.ProyectoTicket{}, + &models.TicketMensaje{}, + &models.Factura{}, + ); err != nil { + log.Printf("[MIGRATE] Error en MigratePortal: %v", err) + } else { + log.Println("[MIGRATE] Tablas de Portal OK") + } +} + // MigrateRenovaciones crea/actualiza las tablas del módulo de Renovaciones. // Es idempotente: GORM AutoMigrate solo añade columnas/tablas nuevas, nunca las borra. func MigrateRenovaciones() { diff --git a/pkg/models/portal_user.go b/pkg/models/portal_user.go index f9978a9..6f1070b 100644 --- a/pkg/models/portal_user.go +++ b/pkg/models/portal_user.go @@ -14,14 +14,16 @@ import ( // - Rol "partner": accede a los proyectos de todos sus ClienteIDs via PortalAccesos. type PortalUser struct { gorm.Model - Nombre string `json:"nombre" gorm:"column:nombre;not null"` - Email string `json:"email" gorm:"column:email;uniqueIndex;not null"` - Password string `json:"-" gorm:"column:password;type:text"` - ClienteID *uint `json:"cliente_id" gorm:"column:cliente_id;index"` // nil si es partner - Cliente *Cliente `json:"cliente" gorm:"foreignKey:ClienteID"` - Rol string `json:"rol" gorm:"column:rol;default:'cliente'"` // cliente|partner - Activo bool `json:"activo" gorm:"column:activo;default:true"` - Notas string `json:"notas" gorm:"column:notas;type:text"` + Nombre string `json:"nombre" gorm:"column:nombre;not null"` + Email string `json:"email" gorm:"column:email;uniqueIndex;not null"` + Password string `json:"-" gorm:"column:password;type:text"` + ClienteID *uint `json:"cliente_id" gorm:"column:cliente_id;index"` + Cliente *Cliente `json:"cliente" gorm:"foreignKey:ClienteID"` + Rol string `json:"rol" gorm:"column:rol;default:'cliente'"` + RoleID *uint `json:"role_id" gorm:"column:role_id;index"` + Role *Roles `json:"role" gorm:"foreignKey:RoleID"` + Activo bool `json:"activo" gorm:"column:activo;default:true"` + Notas string `json:"notas" gorm:"column:notas;type:text"` PortalAccesos []PortalAcceso `json:"portal_accesos" gorm:"foreignKey:PortalUserID"` } @@ -43,7 +45,7 @@ func (PortalAcceso) TableName() string { return "portal_accesos" } func GetAllPortalUsers(limit, offset int) ([]PortalUser, int64, error) { var items []PortalUser var total int64 - db := app.Http.Database.DB.Model(&PortalUser{}).Preload("Cliente").Preload("PortalAccesos.Cliente") + db := app.Http.Database.DB.Model(&PortalUser{}).Preload("Cliente").Preload("PortalAccesos.Cliente").Preload("Role") if err := db.Count(&total).Error; err != nil { return nil, 0, err } @@ -55,7 +57,7 @@ func GetAllPortalUsers(limit, offset int) ([]PortalUser, int64, error) { func GetPortalUserByID(id uint) (*PortalUser, error) { var item PortalUser - err := app.Http.Database.DB.Preload("Cliente").Preload("PortalAccesos.Cliente").First(&item, id).Error + err := app.Http.Database.DB.Preload("Cliente").Preload("PortalAccesos.Cliente").Preload("Role").First(&item, id).Error return &item, err } @@ -75,6 +77,7 @@ func UpdatePortalUser(u *PortalUser) error { "email": u.Email, "cliente_id": u.ClienteID, "rol": u.Rol, + "role_id": u.RoleID, "activo": u.Activo, "notas": u.Notas, }).Error @@ -112,7 +115,11 @@ func RemovePortalAcceso(portalUserID, clienteID uint) error { // GetClienteIDsForPortalUser devuelve todos los clienteIDs accesibles para un portal user. func GetClienteIDsForPortalUser(u *PortalUser) []uint { - if u.Rol == "partner" { + isPartner := u.Rol == "partner" + if u.Role != nil { + isPartner = u.Role.EsPortalPartner + } + if isPartner { ids := make([]uint, 0, len(u.PortalAccesos)) for _, a := range u.PortalAccesos { ids = append(ids, a.ClienteID) diff --git a/pkg/models/roles.go b/pkg/models/roles.go index 88dc389..0b2bdbe 100755 --- a/pkg/models/roles.go +++ b/pkg/models/roles.go @@ -9,11 +9,13 @@ import ( type Roles struct { gorm.Model - ID uint `gorm:"primarykey"` - CreatedAt time.Time `json:"created_at" gorm:"column:created_at"` - Description string `json:"description" gorm:"column:description"` - Name string `json:"name" gorm:"column:name"` - Submodules []Submodules `json:"submodules" gorm:"many2many:roles_submodules"` // Asegúrate de que Submodules esté definido + ID uint `gorm:"primarykey"` + CreatedAt time.Time `json:"created_at" gorm:"column:created_at"` + Description string `json:"description" gorm:"column:description"` + Name string `json:"name" gorm:"column:name"` + EsPortalCliente bool `json:"es_portal_cliente" gorm:"column:es_portal_cliente;default:false"` + EsPortalPartner bool `json:"es_portal_partner" gorm:"column:es_portal_partner;default:false"` + Submodules []Submodules `json:"submodules" gorm:"many2many:roles_submodules"` } // TableName overrides the table name used by Modules to `modules` @@ -88,3 +90,13 @@ func FindRoleByName(name string) (Roles, error) { } return role, nil } + +// GetPortalRoles devuelve los roles marcados como portal cliente o portal partner. +func GetPortalRoles() ([]Roles, error) { + var roles []Roles + err := app.Http.Database.DB. + Where("es_portal_cliente = ? OR es_portal_partner = ?", true, true). + Order("name ASC"). + Find(&roles).Error + return roles, err +} diff --git a/resources/views/portal_usuarios.html b/resources/views/portal_usuarios.html index 8afe904..96a59df 100644 --- a/resources/views/portal_usuarios.html +++ b/resources/views/portal_usuarios.html @@ -33,13 +33,13 @@