feat: registrar proyectos con fases, adjuntar documentos y asignar tareas por Telegram
- crear_fase_proyecto: agrega fases/etapas a un proyecto (se puede llamar varias veces seguidas para cargar todas las fases de un proyecto nuevo). - adjuntar_documento_proyecto: guarda el archivo que el usuario acaba de enviar por Telegram como documento del proyecto (mismo mecanismo de adjuntos ya usado para facturas — se generalizó TelegramAttachment para servir a ambos casos). - listar_usuarios + asignado_id en crear_tarea + asignar_tarea: permite asignar tareas a alguien del equipo por Telegram, disparando la misma notificación (Telegram/email/sistema) que ya dispara el dashboard. - El prompt del sistema ahora indica cómo decidir entre adjuntar_factura y adjuntar_documento_proyecto según el contexto del archivo recibido. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
cd0ca6d232
commit
a0b2e9ae0a
@@ -0,0 +1,73 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
)
|
||||
|
||||
// CrearTareaAsignada crea una tarea, opcionalmente ya asignada a alguien, y
|
||||
// dispara la notificación correspondiente (Telegram/email/sistema, según la
|
||||
// config de notif_evento_configs) si quedó asignada a un usuario.
|
||||
func CrearTareaAsignada(titulo, descripcion, estado, prioridad string, asignadoID *uint, fechaLimite *time.Time) (*models.Tarea, error) {
|
||||
if titulo == "" {
|
||||
return nil, fmt.Errorf("titulo requerido")
|
||||
}
|
||||
if estado == "" {
|
||||
estado = "pendiente"
|
||||
}
|
||||
if prioridad == "" {
|
||||
prioridad = "media"
|
||||
}
|
||||
t := &models.Tarea{
|
||||
Titulo: titulo,
|
||||
Descripcion: descripcion,
|
||||
Estado: estado,
|
||||
Prioridad: prioridad,
|
||||
AsignadoID: asignadoID,
|
||||
FechaLimite: fechaLimite,
|
||||
}
|
||||
if err := models.CreateTarea(t); err != nil {
|
||||
return nil, fmt.Errorf("no se pudo crear la tarea: %w", err)
|
||||
}
|
||||
if asignadoID != nil {
|
||||
if full, err := models.GetTareaByID(t.ID); err == nil {
|
||||
go NotificarTareaAsignada(full)
|
||||
}
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// AsignarTarea cambia el responsable de una tarea existente y notifica al nuevo
|
||||
// asignado si el responsable realmente cambió. asignadoID puede ser nil para
|
||||
// dejar la tarea sin asignar.
|
||||
func AsignarTarea(id uint, asignadoID *uint) (*models.Tarea, error) {
|
||||
if id == 0 {
|
||||
return nil, fmt.Errorf("id requerido")
|
||||
}
|
||||
tarea, err := models.GetTareaByID(id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tarea no encontrada: %w", err)
|
||||
}
|
||||
prevAsignado := tarea.AsignadoID
|
||||
tarea.AsignadoID = asignadoID
|
||||
if err := models.SaveTarea(tarea); err != nil {
|
||||
return nil, fmt.Errorf("no se pudo asignar la tarea: %w", err)
|
||||
}
|
||||
full, _ := models.GetTareaByID(id)
|
||||
if cambioAsignado(prevAsignado, asignadoID) && full != nil {
|
||||
go NotificarTareaAsignada(full)
|
||||
}
|
||||
return full, nil
|
||||
}
|
||||
|
||||
func cambioAsignado(a, b *uint) bool {
|
||||
if a == nil && b == nil {
|
||||
return false
|
||||
}
|
||||
if a == nil || b == nil {
|
||||
return true
|
||||
}
|
||||
return *a != *b
|
||||
}
|
||||
Reference in New Issue
Block a user