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.
478 lines
22 KiB
PHP
478 lines
22 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/../../src/Auth.php';
|
|
require_once __DIR__ . '/../../src/Db.php';
|
|
require_once __DIR__ . '/../../src/AuditLog.php';
|
|
|
|
if (($_GET['action'] ?? '') === 'logout') {
|
|
header('Location: /auth/logout.php');
|
|
exit;
|
|
}
|
|
|
|
Auth::requireAuth();
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(204); exit; }
|
|
|
|
const DEPTS = ['adm', 'corp', 'mig', 'lit'];
|
|
const PREFIX = ['adm' => 'ADM', 'corp' => 'CRP', 'mig' => 'MIG', 'lit' => 'LIT'];
|
|
const STATUS_MAP = [
|
|
'adm' => ['Solicitado','Recibido','En Proceso','Notificado','Recurso','Culminado','Facturado'],
|
|
'corp' => ['Solicitado','Recibido','Borrador','Versión de Firma','Firmado','Culminado','Facturado'],
|
|
'mig' => ['Solicitado','Recibido','Presentado','Notificado','Recurso','Culminado','Facturado'],
|
|
'lit' => ['Solicitado','Recibido','Presentado','Admitido','Contestado','Pruebas','Contrapruebas','Alegatos','Sentencia','Apelación'],
|
|
];
|
|
|
|
function ok($data = null): void {
|
|
echo json_encode(['ok' => true, 'data' => $data, 'user' => Auth::user()], JSON_UNESCAPED_UNICODE);
|
|
exit;
|
|
}
|
|
|
|
function err(string $msg, int $code = 400): void {
|
|
http_response_code($code);
|
|
echo json_encode(['ok' => false, 'error' => $msg], JSON_UNESCAPED_UNICODE);
|
|
exit;
|
|
}
|
|
|
|
function body(): array {
|
|
return json_decode((string) file_get_contents('php://input'), true) ?? [];
|
|
}
|
|
|
|
function dept_of(array $b): string {
|
|
$d = strtolower((string)($b['departamento'] ?? $_GET['dept'] ?? ''));
|
|
if (!in_array($d, DEPTS, true)) err('Departamento inválido');
|
|
return $d;
|
|
}
|
|
|
|
function clean_yesno(?string $v): ?string {
|
|
if ($v === null) return null;
|
|
$v = trim($v);
|
|
if ($v === '') return null;
|
|
return in_array($v, ['Sí','No'], true) ? $v : null;
|
|
}
|
|
|
|
function clean_date(?string $v): ?string {
|
|
if (!$v) return null;
|
|
$v = trim($v);
|
|
if ($v === '') return null;
|
|
return preg_match('/^\d{4}-\d{2}-\d{2}$/', $v) ? $v : null;
|
|
}
|
|
|
|
function next_codigo(PDO $pdo, string $dept): string {
|
|
$pdo->beginTransaction();
|
|
try {
|
|
$sel = $pdo->prepare('SELECT next_seq FROM tramites_seq WHERE departamento = :d FOR UPDATE');
|
|
$sel->execute([':d' => $dept]);
|
|
$n = (int) ($sel->fetchColumn() ?: 1);
|
|
|
|
$upd = $pdo->prepare('UPDATE tramites_seq SET next_seq = :n WHERE departamento = :d');
|
|
$upd->execute([':n' => $n + 1, ':d' => $dept]);
|
|
|
|
$pdo->commit();
|
|
return sprintf('%s-%03d', PREFIX[$dept], $n);
|
|
} catch (Throwable $e) {
|
|
$pdo->rollBack();
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
function hydrate(PDO $pdo, array $row): array {
|
|
$tid = (int) $row['id'];
|
|
|
|
$obs = $pdo->prepare('SELECT id, texto, abogado, autor_email, fecha FROM tramites_obs WHERE tramite_id = :t ORDER BY fecha ASC');
|
|
$obs->execute([':t' => $tid]);
|
|
$row['obs'] = $obs->fetchAll();
|
|
|
|
$hrs = $pdo->prepare('SELECT id, abogado, hrs, descripcion, autor_email, fecha FROM tramites_hours WHERE tramite_id = :t ORDER BY fecha ASC');
|
|
$hrs->execute([':t' => $tid]);
|
|
$row['hours'] = array_map(function ($h) {
|
|
$h['hrs'] = (float) $h['hrs'];
|
|
return $h;
|
|
}, $hrs->fetchAll());
|
|
|
|
$inv = $pdo->prepare(
|
|
'SELECT u.id, u.email, u.name
|
|
FROM tramites_involucrados ti
|
|
JOIN users u ON u.id = ti.user_id
|
|
WHERE ti.tramite_id = :t
|
|
ORDER BY u.name ASC, u.email ASC'
|
|
);
|
|
$inv->execute([':t' => $tid]);
|
|
$row['involucrados'] = array_map(function ($u) {
|
|
$u['id'] = (int)$u['id'];
|
|
return $u;
|
|
}, $inv->fetchAll());
|
|
|
|
return $row;
|
|
}
|
|
|
|
/**
|
|
* ¿El usuario actual puede ver/editar este trámite?
|
|
* Socio → siempre
|
|
* Resto → si es creador, o abogado solicitante (name), o involucrado
|
|
*/
|
|
function canView(PDO $pdo, int $tid): bool {
|
|
if (Auth::isSocio()) return true;
|
|
$email = Auth::user()['email'];
|
|
$uid = Auth::userId();
|
|
$stmt = $pdo->prepare(
|
|
"SELECT 1 FROM tramites_legales t
|
|
LEFT JOIN users ua ON ua.name = t.abogado AND ua.activo = 1
|
|
LEFT JOIN tramites_involucrados ti ON ti.tramite_id = t.id AND ti.user_id = :uid
|
|
WHERE t.id = :tid
|
|
AND (t.creado_por = :email OR ua.id = :uid2 OR ti.user_id IS NOT NULL)
|
|
LIMIT 1"
|
|
);
|
|
$stmt->execute([':tid' => $tid, ':email' => $email, ':uid' => $uid, ':uid2' => $uid]);
|
|
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]);
|
|
if (empty($userIds)) return;
|
|
$placeholders = implode(',', array_fill(0, count($userIds), '?'));
|
|
$check = $pdo->prepare("SELECT id FROM users WHERE activo = 1 AND id IN ($placeholders)");
|
|
$check->execute(array_map('intval', $userIds));
|
|
$valid = array_map('intval', $check->fetchAll(PDO::FETCH_COLUMN));
|
|
if (!$valid) return;
|
|
$ins = $pdo->prepare('INSERT INTO tramites_involucrados (tramite_id, user_id, added_by) VALUES (?,?,?)');
|
|
foreach ($valid as $uid) $ins->execute([$tid, $uid, $addedBy]);
|
|
}
|
|
|
|
$method = $_SERVER['REQUEST_METHOD'];
|
|
$action = $_GET['action'] ?? '';
|
|
$user = Auth::user();
|
|
$myId = Auth::userId();
|
|
$pdo = Db::pdo();
|
|
|
|
try {
|
|
if ($method === 'GET' && $action === 'list') {
|
|
if (Auth::isSocio()) {
|
|
$rows = $pdo->query('SELECT * FROM tramites_legales ORDER BY id DESC')->fetchAll();
|
|
} else {
|
|
$stmt = $pdo->prepare(
|
|
"SELECT DISTINCT t.* FROM tramites_legales t
|
|
LEFT JOIN users ua ON ua.name = t.abogado AND ua.activo = 1
|
|
LEFT JOIN tramites_involucrados ti ON ti.tramite_id = t.id AND ti.user_id = :uid
|
|
WHERE t.creado_por = :email
|
|
OR ua.id = :uid2
|
|
OR ti.user_id IS NOT NULL
|
|
ORDER BY t.id DESC"
|
|
);
|
|
$stmt->execute([':email' => $user['email'], ':uid' => $myId, ':uid2' => $myId]);
|
|
$rows = $stmt->fetchAll();
|
|
}
|
|
$grouped = ['adm' => [], 'corp' => [], 'mig' => [], 'lit' => []];
|
|
foreach ($rows as $r) {
|
|
$grouped[$r['departamento']][] = hydrate($pdo, $r);
|
|
}
|
|
ok($grouped);
|
|
}
|
|
|
|
if ($method === 'POST' && $action === 'create') {
|
|
if (!Auth::canCreate()) err('Tu rol no permite crear trámites. Solo Socios y Abogados pueden.', 403);
|
|
|
|
$b = body();
|
|
$dept = dept_of($b);
|
|
|
|
$est = (string) ($b['estatus'] ?? 'Solicitado');
|
|
if (!in_array($est, STATUS_MAP[$dept], true)) $est = STATUS_MAP[$dept][0];
|
|
|
|
$codigo = next_codigo($pdo, $dept);
|
|
|
|
$stmt = $pdo->prepare(
|
|
'INSERT INTO tramites_legales
|
|
(codigo, departamento, cliente, abogado, estatus, instrucciones,
|
|
nombre, institucion, tipo_documento, tipo_tramite,
|
|
doc_completa, permiso_trabajo, dependientes, fecha_vencimiento,
|
|
esfera, instancia, circuito, juzgado, tipo_proceso,
|
|
incidentes, amparo, fecha_termino, creado_por)
|
|
VALUES
|
|
(:codigo, :dept, :cliente, :abogado, :estatus, :instrucciones,
|
|
:nombre, :institucion, :tipo_documento, :tipo_tramite,
|
|
:doc_completa, :permiso_trabajo, :dependientes, :fecha_vencimiento,
|
|
:esfera, :instancia, :circuito, :juzgado, :tipo_proceso,
|
|
:incidentes, :amparo, :fecha_termino, :user)'
|
|
);
|
|
$stmt->execute([
|
|
':codigo' => $codigo,
|
|
':dept' => $dept,
|
|
':cliente' => (string)($b['cliente'] ?? ''),
|
|
':abogado' => (string)($b['abogado'] ?? ''),
|
|
':estatus' => $est,
|
|
':instrucciones' => (string)($b['instrucciones'] ?? ''),
|
|
':nombre' => (string)($b['nombre'] ?? ''),
|
|
':institucion' => (string)($b['institucion'] ?? ''),
|
|
':tipo_documento'=> (string)($b['tipoDocumento'] ?? ''),
|
|
':tipo_tramite' => (string)($b['tipoTramite'] ?? ''),
|
|
':doc_completa' => clean_yesno($b['docCompleta'] ?? null),
|
|
':permiso_trabajo'=> clean_yesno($b['permisoTrabajo'] ?? null),
|
|
':dependientes' => clean_yesno($b['dependientes'] ?? null),
|
|
':fecha_vencimiento' => clean_date($b['fechaVencimiento'] ?? null),
|
|
':esfera' => in_array($b['esfera'] ?? '', ['Civil','Penal'], true) ? $b['esfera'] : null,
|
|
':instancia' => in_array($b['instancia'] ?? '', ['Primera','Segunda','CSJ'], true) ? $b['instancia'] : null,
|
|
':circuito' => (string)($b['circuito'] ?? ''),
|
|
':juzgado' => (string)($b['juzgado'] ?? ''),
|
|
':tipo_proceso' => (string)($b['tipoProceso'] ?? ''),
|
|
':incidentes' => clean_yesno($b['incidentes'] ?? null),
|
|
':amparo' => clean_yesno($b['amparo'] ?? null),
|
|
':fecha_termino' => clean_date($b['fechaTermino'] ?? null),
|
|
':user' => $user['email'],
|
|
]);
|
|
$id = (int) $pdo->lastInsertId();
|
|
|
|
// Involucrados: si vienen del payload, se respetan; si no, se auto-incluye al creador
|
|
$involIds = array_map('intval', (array)($b['involucrados'] ?? []));
|
|
if ($myId > 0 && !in_array($myId, $involIds, true)) $involIds[] = $myId;
|
|
syncInvolucrados($pdo, $id, $involIds, $user['email']);
|
|
|
|
AuditLog::log('tramites', 'create', 'tramite_legal', $codigo, $codigo, ['departamento'=>$dept, 'cliente'=>$b['cliente']??'']);
|
|
|
|
$row = $pdo->prepare('SELECT * FROM tramites_legales WHERE id = :id');
|
|
$row->execute([':id' => $id]);
|
|
ok(hydrate($pdo, $row->fetch()));
|
|
}
|
|
|
|
if ($method === 'PUT' && $action === 'update') {
|
|
$b = body();
|
|
$id = (int) ($b['_id'] ?? 0);
|
|
if (!$id) err('id requerido');
|
|
|
|
if (!canView($pdo, $id)) err('No tienes acceso a este trámite', 403);
|
|
|
|
$cur = $pdo->prepare('SELECT * FROM tramites_legales WHERE id = :id');
|
|
$cur->execute([':id' => $id]);
|
|
$before = $cur->fetch();
|
|
if (!$before) err('Trámite no encontrado', 404);
|
|
|
|
$dept = $before['departamento'];
|
|
$est = (string) ($b['estatus'] ?? $before['estatus']);
|
|
if (!in_array($est, STATUS_MAP[$dept], true)) $est = $before['estatus'];
|
|
|
|
$stmt = $pdo->prepare(
|
|
'UPDATE tramites_legales SET
|
|
cliente=:cliente, abogado=:abogado, estatus=:estatus, instrucciones=:instrucciones,
|
|
nombre=:nombre, institucion=:institucion,
|
|
tipo_documento=:tipo_documento, tipo_tramite=:tipo_tramite,
|
|
doc_completa=:doc_completa, permiso_trabajo=:permiso_trabajo,
|
|
dependientes=:dependientes, fecha_vencimiento=:fecha_vencimiento,
|
|
esfera=:esfera, instancia=:instancia, circuito=:circuito,
|
|
juzgado=:juzgado, tipo_proceso=:tipo_proceso,
|
|
incidentes=:incidentes, amparo=:amparo, fecha_termino=:fecha_termino,
|
|
actualizado_por=:user
|
|
WHERE id=:id'
|
|
);
|
|
$stmt->execute([
|
|
':cliente' => (string)($b['cliente'] ?? $before['cliente']),
|
|
':abogado' => (string)($b['abogado'] ?? $before['abogado']),
|
|
':estatus' => $est,
|
|
':instrucciones' => (string)($b['instrucciones'] ?? $before['instrucciones']),
|
|
':nombre' => (string)($b['nombre'] ?? $before['nombre']),
|
|
':institucion' => (string)($b['institucion'] ?? $before['institucion']),
|
|
':tipo_documento'=> (string)($b['tipoDocumento'] ?? $before['tipo_documento']),
|
|
':tipo_tramite' => (string)($b['tipoTramite'] ?? $before['tipo_tramite']),
|
|
':doc_completa' => clean_yesno($b['docCompleta'] ?? $before['doc_completa']),
|
|
':permiso_trabajo'=> clean_yesno($b['permisoTrabajo'] ?? $before['permiso_trabajo']),
|
|
':dependientes' => clean_yesno($b['dependientes'] ?? $before['dependientes']),
|
|
':fecha_vencimiento' => clean_date($b['fechaVencimiento'] ?? $before['fecha_vencimiento']),
|
|
':esfera' => in_array(($b['esfera'] ?? $before['esfera']), ['Civil','Penal'], true) ? ($b['esfera'] ?? $before['esfera']) : null,
|
|
':instancia' => in_array(($b['instancia'] ?? $before['instancia']), ['Primera','Segunda','CSJ'], true) ? ($b['instancia'] ?? $before['instancia']) : null,
|
|
':circuito' => (string)($b['circuito'] ?? $before['circuito']),
|
|
':juzgado' => (string)($b['juzgado'] ?? $before['juzgado']),
|
|
':tipo_proceso' => (string)($b['tipoProceso'] ?? $before['tipo_proceso']),
|
|
':incidentes' => clean_yesno($b['incidentes'] ?? $before['incidentes']),
|
|
':amparo' => clean_yesno($b['amparo'] ?? $before['amparo']),
|
|
':fecha_termino' => clean_date($b['fechaTermino'] ?? $before['fecha_termino']),
|
|
':user' => $user['email'],
|
|
':id' => $id,
|
|
]);
|
|
|
|
if (array_key_exists('involucrados', $b) && is_array($b['involucrados'])) {
|
|
syncInvolucrados($pdo, $id, array_map('intval', $b['involucrados']), $user['email']);
|
|
}
|
|
|
|
AuditLog::log('tramites', 'update', 'tramite_legal', $before['codigo'], $before['codigo']);
|
|
|
|
$row = $pdo->prepare('SELECT * FROM tramites_legales WHERE id = :id');
|
|
$row->execute([':id' => $id]);
|
|
ok(hydrate($pdo, $row->fetch()));
|
|
}
|
|
|
|
if ($method === 'PATCH' && $action === 'set_status') {
|
|
$b = body();
|
|
$id = (int) ($b['_id'] ?? 0);
|
|
$val = (string) ($b['estatus'] ?? '');
|
|
if (!$id) err('id requerido');
|
|
|
|
if (!canView($pdo, $id)) err('No tienes acceso a este trámite', 403);
|
|
|
|
$cur = $pdo->prepare('SELECT departamento, codigo FROM tramites_legales WHERE id = :id');
|
|
$cur->execute([':id' => $id]);
|
|
$curRow = $cur->fetch();
|
|
if (!$curRow) err('Trámite no encontrado', 404);
|
|
$dept = $curRow['departamento'];
|
|
if (!in_array($val, STATUS_MAP[$dept], true)) err('Estatus inválido para el departamento');
|
|
|
|
$pdo->prepare('UPDATE tramites_legales SET estatus = :s, actualizado_por = :u WHERE id = :id')
|
|
->execute([':s' => $val, ':u' => $user['email'], ':id' => $id]);
|
|
AuditLog::log('tramites', 'set_status', 'tramite_legal', $curRow['codigo'], $curRow['codigo'], ['estatus'=>$val]);
|
|
ok(['id' => $id, 'estatus' => $val]);
|
|
}
|
|
|
|
if ($method === 'POST' && $action === 'add_obs') {
|
|
$b = body();
|
|
$id = (int) ($b['_id'] ?? 0);
|
|
$texto = trim((string)($b['texto'] ?? ''));
|
|
$abog = trim((string)($b['abogado'] ?? ''));
|
|
if (!$id) err('id requerido');
|
|
if ($texto === '') err('texto requerido');
|
|
|
|
if (!canView($pdo, $id)) err('No tienes acceso a este trámite', 403);
|
|
|
|
$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]);
|
|
|
|
$codSel = $pdo->prepare('SELECT codigo FROM tramites_legales WHERE id = :id');
|
|
$codSel->execute([':id' => $id]);
|
|
$codigo = (string)$codSel->fetchColumn();
|
|
AuditLog::log('tramites', 'add_obs', 'tramite_legal', $codigo, $codigo, ['abogado'=>$abog, 'texto'=>$texto]);
|
|
|
|
$row = $pdo->prepare('SELECT * FROM tramites_legales WHERE id = :id');
|
|
$row->execute([':id' => $id]);
|
|
ok(hydrate($pdo, $row->fetch()));
|
|
}
|
|
|
|
if ($method === 'POST' && $action === 'add_hours') {
|
|
$b = body();
|
|
$id = (int) ($b['_id'] ?? 0);
|
|
$abog = trim((string)($b['abogado'] ?? ''));
|
|
$hrs = (float) ($b['hrs'] ?? 0);
|
|
$desc = trim((string)($b['descripcion'] ?? ''));
|
|
if (!$id) err('id requerido');
|
|
if ($hrs <= 0) err('horas debe ser > 0');
|
|
|
|
if (!canView($pdo, $id)) err('No tienes acceso a este trámite', 403);
|
|
|
|
$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]);
|
|
|
|
$codSel = $pdo->prepare('SELECT codigo FROM tramites_legales WHERE id = :id');
|
|
$codSel->execute([':id' => $id]);
|
|
$codigo = (string)$codSel->fetchColumn();
|
|
AuditLog::log('tramites', 'add_hours', 'tramite_legal', $codigo, $codigo, ['abogado'=>$abog, 'hrs'=>$hrs]);
|
|
|
|
$row = $pdo->prepare('SELECT * FROM tramites_legales WHERE id = :id');
|
|
$row->execute([':id' => $id]);
|
|
ok(hydrate($pdo, $row->fetch()));
|
|
}
|
|
|
|
if ($method === 'PUT' && $action === 'update_hours') {
|
|
$b = body();
|
|
$hourId = (int)($b['_id'] ?? 0);
|
|
if (!$hourId) err('id requerido');
|
|
|
|
$sel = $pdo->prepare('SELECT id, tramite_id, autor_email, abogado, hrs, descripcion FROM tramites_hours WHERE id = :id');
|
|
$sel->execute([':id' => $hourId]);
|
|
$row = $sel->fetch();
|
|
if (!$row) err('Registro de horas no encontrado', 404);
|
|
|
|
$tramiteId = (int)$row['tramite_id'];
|
|
if (!canView($pdo, $tramiteId)) err('No tienes acceso al trámite', 403);
|
|
// Cualquiera que pueda ver el trámite (creador, abogado solicitante,
|
|
// involucrado, o socio/admin) puede editar las horas registradas.
|
|
|
|
$abog = trim((string)($b['abogado'] ?? $row['abogado']));
|
|
$hrs = (float) ($b['hrs'] ?? $row['hrs']);
|
|
$desc = trim((string)($b['descripcion'] ?? $row['descripcion']));
|
|
if ($hrs <= 0) err('horas debe ser > 0');
|
|
|
|
$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]);
|
|
|
|
$codSel = $pdo->prepare('SELECT codigo FROM tramites_legales WHERE id = :id');
|
|
$codSel->execute([':id' => $tramiteId]);
|
|
$codigo = (string)$codSel->fetchColumn();
|
|
AuditLog::log('tramites', 'update_hours', 'hour', (string)$hourId, $codigo, ['abogado'=>$abog, 'hrs'=>$hrs]);
|
|
|
|
$r = $pdo->prepare('SELECT * FROM tramites_legales WHERE id = :id');
|
|
$r->execute([':id' => $tramiteId]);
|
|
ok(hydrate($pdo, $r->fetch()));
|
|
}
|
|
|
|
if ($method === 'DELETE' && $action === 'delete_hours') {
|
|
$hourId = (int)($_GET['id'] ?? 0);
|
|
if (!$hourId) err('id requerido');
|
|
|
|
$sel = $pdo->prepare('SELECT id, tramite_id, autor_email FROM tramites_hours WHERE id = :id');
|
|
$sel->execute([':id' => $hourId]);
|
|
$row = $sel->fetch();
|
|
if (!$row) err('Registro de horas no encontrado', 404);
|
|
|
|
$tramiteId = (int)$row['tramite_id'];
|
|
if (!canView($pdo, $tramiteId)) err('No tienes acceso al trámite', 403);
|
|
// Misma regla que update_hours: cualquiera con acceso al trámite puede eliminar.
|
|
|
|
$pdo->prepare('DELETE FROM tramites_hours WHERE id = :id')->execute([':id' => $hourId]);
|
|
$pdo->prepare('UPDATE tramites_legales SET actualizado_por = :u WHERE id = :id')
|
|
->execute([':u' => $user['email'], ':id' => $tramiteId]);
|
|
|
|
$codSel = $pdo->prepare('SELECT codigo FROM tramites_legales WHERE id = :id');
|
|
$codSel->execute([':id' => $tramiteId]);
|
|
$codigo = (string)$codSel->fetchColumn();
|
|
AuditLog::log('tramites', 'delete_hours', 'hour', (string)$hourId, $codigo);
|
|
|
|
$r = $pdo->prepare('SELECT * FROM tramites_legales WHERE id = :id');
|
|
$r->execute([':id' => $tramiteId]);
|
|
ok(hydrate($pdo, $r->fetch()));
|
|
}
|
|
|
|
if ($method === 'DELETE' && $action === 'delete') {
|
|
if (!Auth::canDelete()) err('Tu rol no permite eliminar trámites. Solo Socios y Abogados pueden.', 403);
|
|
|
|
$id = (int) ($_GET['id'] ?? 0);
|
|
if (!$id) err('id requerido');
|
|
|
|
if (!canView($pdo, $id)) err('No tienes acceso a este trámite', 403);
|
|
|
|
$codSel = $pdo->prepare('SELECT codigo FROM tramites_legales WHERE id = :id');
|
|
$codSel->execute([':id' => $id]);
|
|
$codigo = (string)$codSel->fetchColumn();
|
|
|
|
$pdo->prepare('DELETE FROM tramites_legales WHERE id = :id')->execute([':id' => $id]);
|
|
AuditLog::log('tramites', 'delete', 'tramite_legal', $codigo, $codigo);
|
|
ok(['deleted' => $id]);
|
|
}
|
|
|
|
err('Acción no reconocida', 404);
|
|
|
|
} catch (PDOException $e) {
|
|
error_log('tramites db error: ' . $e->getMessage());
|
|
err('Error de base de datos', 500);
|
|
} catch (Throwable $e) {
|
|
error_log('tramites error: ' . $e->getMessage());
|
|
err('Error interno', 500);
|
|
}
|