refactor(hours): FK user_id en tramites_hours y tramites_obs

Hasta ahora el vínculo "esta hora/observación es de X" era por string
(h.abogado = users.name). Se rompía cuando un Socio renombraba un
usuario en el Panel de Control (las entradas históricas conservaban
el nombre viejo y los filtros del Reporte de Horas no las hallaban).

- Migración 014: ADD COLUMN user_id INT NULL + FK ON DELETE SET NULL
  en ambas tablas, con backfill via JOIN users.name = abogado
- tramites/api.php: helper userIdByName() + add_obs/add_hours/
  update_hours ahora persisten user_id junto con el string abogado
- horas/api.php: filtro WHERE (user_id = :uid OR (user_id IS NULL
  AND abogado = :name)) — prioriza FK, cae al string solo para
  filas legacy sin user_id. by_user y by_user_tramite agrupan por
  COALESCE(u.name, h.abogado) para usar siempre el nombre actual.
This commit is contained in:
Soporte ZH Consultores
2026-06-04 22:33:41 -05:00
parent eff590af47
commit 0a8dc6fc46
3 changed files with 97 additions and 27 deletions
+18 -6
View File
@@ -128,6 +128,15 @@ function canView(PDO $pdo, int $tid): bool {
return $stmt->fetchColumn() !== false;
}
/** Resuelve el user_id (activo) a partir del nombre completo; null si no match. */
function userIdByName(PDO $pdo, string $name): ?int {
if ($name === '') return null;
$stmt = $pdo->prepare('SELECT id FROM users WHERE name = :n AND activo = 1 LIMIT 1');
$stmt->execute([':n' => $name]);
$id = $stmt->fetchColumn();
return $id === false ? null : (int)$id;
}
/** Reemplaza la lista de involucrados del trámite por la lista dada (array de user_id). */
function syncInvolucrados(PDO $pdo, int $tid, array $userIds, string $addedBy): void {
$pdo->prepare('DELETE FROM tramites_involucrados WHERE tramite_id = :t')->execute([':t' => $tid]);
@@ -331,8 +340,9 @@ try {
if (!canView($pdo, $id)) err('No tienes acceso a este trámite', 403);
$pdo->prepare('INSERT INTO tramites_obs (tramite_id, texto, abogado, autor_email) VALUES (?,?,?,?)')
->execute([$id, $texto, $abog, $user['email']]);
$uidObs = userIdByName($pdo, $abog);
$pdo->prepare('INSERT INTO tramites_obs (tramite_id, texto, abogado, user_id, autor_email) VALUES (?,?,?,?,?)')
->execute([$id, $texto, $abog, $uidObs, $user['email']]);
$pdo->prepare('UPDATE tramites_legales SET actualizado_por = :u WHERE id = :id')
->execute([':u' => $user['email'], ':id' => $id]);
@@ -358,8 +368,9 @@ try {
if (!canView($pdo, $id)) err('No tienes acceso a este trámite', 403);
$pdo->prepare('INSERT INTO tramites_hours (tramite_id, abogado, hrs, descripcion, autor_email) VALUES (?,?,?,?,?)')
->execute([$id, $abog, $hrs, $desc, $user['email']]);
$uidH = userIdByName($pdo, $abog);
$pdo->prepare('INSERT INTO tramites_hours (tramite_id, abogado, user_id, hrs, descripcion, autor_email) VALUES (?,?,?,?,?,?)')
->execute([$id, $abog, $uidH, $hrs, $desc, $user['email']]);
$pdo->prepare('UPDATE tramites_legales SET actualizado_por = :u WHERE id = :id')
->execute([':u' => $user['email'], ':id' => $id]);
@@ -394,8 +405,9 @@ try {
$desc = trim((string)($b['descripcion'] ?? $row['descripcion']));
if ($hrs <= 0) err('horas debe ser > 0');
$upd = $pdo->prepare('UPDATE tramites_hours SET abogado = :a, hrs = :h, descripcion = :d WHERE id = :id');
$upd->execute([':a' => $abog, ':h' => $hrs, ':d' => $desc, ':id' => $hourId]);
$uidU = userIdByName($pdo, $abog);
$upd = $pdo->prepare('UPDATE tramites_hours SET abogado = :a, user_id = :uid, hrs = :h, descripcion = :d WHERE id = :id');
$upd->execute([':a' => $abog, ':uid' => $uidU, ':h' => $hrs, ':d' => $desc, ':id' => $hourId]);
$pdo->prepare('UPDATE tramites_legales SET actualizado_por = :u WHERE id = :id')
->execute([':u' => $user['email'], ':id' => $tramiteId]);