── Voz que a veces no suena o se corta ── Dos causas nuevas, ambas intermitentes por naturaleza: 1. Defecto conocido de Chrome: si nada referencia la SpeechSynthesisUtterance, el recolector de basura puede llevársela A MITAD DE FRASE. El audio se corta en seco y 'end' no llega. Depende de cuándo pase el recolector, así que nunca se reproduce a voluntad. Cada locución queda anclada en un Set hasta terminar (_uttAncladas). 2. Tras un cancel(), en Windows y ChromeOS el motor puede quedar en pausa: speak() encola y jamás suena, sin error alguno. resume() antes de cada speak() lo destranca, y sobre un motor sano no hace nada. Y porque lo intermitente no se depura mirando la pantalla, queda una bitácora: cada intento de hablar registra voz elegida, si es local, cuánto tardó en arrancar y cómo terminó — en localStorage.tvVozLog (últimos 200) y en la tabla turnero_tv_log vía sendBeacon (endpoint log_tv.php, insert-only, eventos de lista cerrada). La próxima vez que reporten "ayer a las 10 no sonó", se consulta la tabla y se ve qué pasó exactamente. ── Servicios de RIPS que "se demoran" ── Medido en datos, no en hipótesis: la facturación en el sistema del laboratorio ocurre MIENTRAS la recepcionista atiende. La consulta a RIPS se hacía UNA sola vez, al vincular al paciente — y en 7 días, 547 de 549 registros llegaron DESPUÉS de esa única consulta. Nadie volvía a preguntar: eso es lo que se percibía como lentitud de RIPS. (El scheduler en sí tarda segundos; de paso: el reloj del equipo legado está ~1 hora atrasado, visible en hora_recepcion.) Ahora la ficha sondea cada 10 s hasta 10 minutos y se detiene al encontrar, al limpiar la ficha o al agotar los intentos. Si la recepcionista ya marcó exámenes a mano, no se le pisan: se le ofrece el banner en vez de autocargar. ── Pruebas (22, todas contra el código real extraído de las vistas) ── scripts/test_tv_voz.js 9 anclaje GC, resume(), bloqueo, voz lenta, bitácora scripts/test_rips_sondeo.js 7 reintentos, paradas, tope, sin duplicar scripts/test_rips_ventana.php 6 ventana SQL en tabla TEMPORARY, sin tocar datos Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
85 lines
3.2 KiB
PHP
85 lines
3.2 KiB
PHP
<?php
|
|
/**
|
|
* scripts/test_rips_ventana.php — php scripts/test_rips_ventana.php
|
|
*
|
|
* Prueba la VENTANA de la caché RIPS (la consulta de get_examenes_rips.php)
|
|
* contra la base real, en una tabla TEMPORARY que se esfuma al desconectar:
|
|
* ni toca ni ensucia los datos de producción.
|
|
*
|
|
* Reglas que vigila:
|
|
* - un registro de hace 5 minutos se encuentra;
|
|
* - uno de hace más de 30 minutos NO (ventana);
|
|
* - uno ya asignado a un turno NO (turno_id);
|
|
* - uno de ayer NO (solo el día actual);
|
|
* - de dos del mismo documento gana el más reciente.
|
|
*/
|
|
require_once __DIR__ . '/../config/config.php';
|
|
|
|
$fallos = 0;
|
|
function ok(string $d, bool $c): void {
|
|
global $fallos;
|
|
echo ($c ? ' ok ' : ' FALLA ') . $d . "\n";
|
|
if (!$c) $fallos++;
|
|
}
|
|
|
|
$pdo = Database::getInstance()->getConnection();
|
|
|
|
$pdo->exec("CREATE TEMPORARY TABLE tmp_rips LIKE rips_examenes_pendientes");
|
|
|
|
$ins = $pdo->prepare(
|
|
"INSERT INTO tmp_rips (numero_documento, datos, recepcion_id, hora_recepcion, created_at, turno_id)
|
|
VALUES (?, ?, ?, ?, ?, ?)"
|
|
);
|
|
// (documento, minutos hacia atrás de created_at, turno_id)
|
|
$casos = [
|
|
['1111', 5, null], // reciente y libre → debe aparecer
|
|
['2222', 45, null], // fuera de la ventana de 30 min
|
|
['3333', 5, 999], // ya usado por un turno
|
|
['4444', 1500, null], // de ayer
|
|
['5555', 20, null], // mismo doc, dos registros…
|
|
['5555', 3, null], // …gana el más reciente (marcado v2)
|
|
];
|
|
foreach ($casos as $i => [$doc, $min, $turno]) {
|
|
$ins->execute([
|
|
$doc,
|
|
json_encode([['cod_examen' => 'T' . $i, 'v' => $i === 5 ? 'v2' : 'v1']]),
|
|
1000 + $i,
|
|
'08:00:00',
|
|
date('Y-m-d H:i:s', time() - $min * 60),
|
|
$turno,
|
|
]);
|
|
}
|
|
|
|
// La MISMA consulta de get_examenes_rips.php, apuntada a la tabla temporal
|
|
$q = $pdo->prepare(
|
|
"SELECT datos FROM tmp_rips
|
|
WHERE numero_documento = ?
|
|
AND DATE(created_at) = CURDATE()
|
|
AND created_at >= NOW() - INTERVAL 30 MINUTE
|
|
AND turno_id IS NULL
|
|
ORDER BY created_at DESC
|
|
LIMIT 1"
|
|
);
|
|
$buscar = function (string $doc) use ($q) {
|
|
$q->execute([$doc]);
|
|
$r = $q->fetch(PDO::FETCH_ASSOC);
|
|
return $r ? json_decode($r['datos'], true) : null;
|
|
};
|
|
|
|
ok('un registro de hace 5 minutos se encuentra', $buscar('1111') !== null);
|
|
ok('uno de hace 45 minutos queda fuera de la ventana', $buscar('2222') === null);
|
|
ok('uno ya asignado a un turno no se reutiliza', $buscar('3333') === null);
|
|
ok('uno de ayer no aparece aunque el documento coincida', $buscar('4444') === null);
|
|
$r = $buscar('5555');
|
|
ok('con dos del mismo documento gana el más reciente', ($r[0]['v'] ?? '') === 'v2');
|
|
|
|
// El re-empuje del scheduler (DELETE + INSERT) refresca created_at, así que un
|
|
// registro viejo que el sistema legado reenvía vuelve a entrar en la ventana.
|
|
$pdo->exec("DELETE FROM tmp_rips WHERE numero_documento = '2222'");
|
|
$ins->execute(['2222', json_encode([['cod_examen' => 'RE']]), 2000, '08:00:00',
|
|
date('Y-m-d H:i:s'), null]);
|
|
ok('un re-empuje del scheduler vuelve a hacer visible el registro', $buscar('2222') !== null);
|
|
|
|
echo "\n" . ($fallos === 0 ? "Todo correcto.\n" : "$fallos pruebas fallaron.\n");
|
|
exit($fallos === 0 ? 0 : 1);
|