Files
soft_usite/pkg/services/tarea_service.go
T
Lizandro GDandClaude Opus 5 5ac70a4d6e fix: tareas del agente invisibles en el Kanban + facturas de compra por Telegram
- El agente creaba tareas con estado='pendiente' (default), pero el tablero
  Kanban del dashboard solo reconoce por_hacer/en_progreso/revision/hecho. La
  tarea se guardaba bien (por eso llegaba el correo de notificación) pero no
  aparecía en ninguna columna. Se corrigen los enums y el default de las tools
  crear_tarea/actualizar_estado_tarea, y se agrega una reparación única al
  arranque que corrige las tareas ya creadas con el estado inválido.

- adjuntar_factura siempre asumía factura de VENTA (ligada a un cliente). Se
  agrega adjuntar_factura_compra: cuando un proveedor le factura a U-SITE (no
  al revés), busca/crea la Entidad proveedor y registra una cuenta por pagar
  con el documento adjunto (se agregan campos archivo/original_name/tipo_mime
  a CuentaPagar, que no los tenía). El prompt del sistema instruye a Claude a
  decidir la dirección leyendo quién emite y quién recibe el documento.
  De paso: endpoint de descarga del soporte de la factura de compra, expuesto
  también en el dashboard (/app/contabilidad/cuentas-pagar).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 14:53:47 +00:00

77 lines
2.1 KiB
Go

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 == "" {
// Debe coincidir con las columnas del Kanban (tareas.html): por_hacer,
// en_progreso, revision, hecho. "pendiente" no es ninguna de esas — una
// tarea con ese estado se guarda pero no aparece en ninguna columna.
estado = "por_hacer"
}
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
}