up
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
/**
|
||||
* API - Exportar conversaciones a CSV
|
||||
*/
|
||||
|
||||
require_once '../config/config.php';
|
||||
|
||||
// Verificar autenticación
|
||||
requireAuthentication();
|
||||
|
||||
// Parámetros de filtro opcionales
|
||||
$phone = trim($_GET['phone'] ?? '');
|
||||
$direction = trim($_GET['direction'] ?? ''); // incoming | outgoing | ''
|
||||
$dateFrom = trim($_GET['date_from'] ?? '');
|
||||
$dateTo = trim($_GET['date_to'] ?? '');
|
||||
|
||||
// Construir WHERE
|
||||
$where = [];
|
||||
$params = [];
|
||||
|
||||
if ($phone !== '') {
|
||||
$where[] = 'u.phone_number LIKE :phone';
|
||||
$params[':phone'] = '%' . $phone . '%';
|
||||
}
|
||||
if (in_array($direction, ['incoming', 'outgoing'], true)) {
|
||||
$where[] = 'c.direction = :direction';
|
||||
$params[':direction'] = $direction;
|
||||
}
|
||||
if ($dateFrom !== '') {
|
||||
$where[] = 'c.created_at >= :date_from';
|
||||
$params[':date_from'] = $dateFrom . ' 00:00:00';
|
||||
}
|
||||
if ($dateTo !== '') {
|
||||
$where[] = 'c.created_at <= :date_to';
|
||||
$params[':date_to'] = $dateTo . ' 23:59:59';
|
||||
}
|
||||
|
||||
$whereSQL = $where ? ('WHERE ' . implode(' AND ', $where)) : '';
|
||||
|
||||
// Nombre de archivo dinámico
|
||||
$filename = 'conversaciones_' . date('Y-m-d');
|
||||
if ($dateFrom || $dateTo) $filename .= '_' . ($dateFrom ?: 'inicio') . '_a_' . ($dateTo ?: 'hoy');
|
||||
$filename .= '.csv';
|
||||
|
||||
// Headers para descarga
|
||||
header('Content-Type: text/csv; charset=utf-8');
|
||||
header('Content-Disposition: attachment; filename="' . $filename . '"');
|
||||
header('Cache-Control: no-cache, must-revalidate');
|
||||
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
$pdo = $db->getConnection();
|
||||
|
||||
$sql = "
|
||||
SELECT
|
||||
c.id AS id,
|
||||
u.phone_number AS telefono,
|
||||
COALESCE(u.name, 'Sin nombre') AS nombre_usuario,
|
||||
c.direction AS direccion,
|
||||
c.message_type AS tipo_mensaje,
|
||||
c.status AS estado,
|
||||
CASE WHEN c.is_read = 1 THEN 'Sí' ELSE 'No' END AS leido,
|
||||
REPLACE(REPLACE(COALESCE(c.content,''), '\r\n', ' '), '\n', ' ')
|
||||
AS contenido,
|
||||
c.media_url AS url_media,
|
||||
c.filename AS archivo,
|
||||
c.created_at AS fecha_hora
|
||||
FROM conversations c
|
||||
INNER JOIN users u ON u.id = c.user_id
|
||||
$whereSQL
|
||||
ORDER BY c.created_at DESC
|
||||
LIMIT 50000
|
||||
";
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
|
||||
$output = fopen('php://output', 'w');
|
||||
|
||||
// BOM UTF-8 para compatibilidad con Excel
|
||||
fprintf($output, chr(0xEF) . chr(0xBB) . chr(0xBF));
|
||||
|
||||
// Encabezados CSV
|
||||
fputcsv($output, [
|
||||
'ID',
|
||||
'Teléfono',
|
||||
'Nombre Usuario',
|
||||
'Dirección',
|
||||
'Tipo Mensaje',
|
||||
'Estado',
|
||||
'Leído',
|
||||
'Contenido',
|
||||
'URL Media',
|
||||
'Archivo',
|
||||
'Fecha y Hora',
|
||||
], ';');
|
||||
|
||||
// Filas
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
fputcsv($output, [
|
||||
$row['id'],
|
||||
$row['telefono'],
|
||||
$row['nombre_usuario'],
|
||||
$row['direccion'],
|
||||
$row['tipo_mensaje'],
|
||||
$row['estado'],
|
||||
$row['leido'],
|
||||
$row['contenido'],
|
||||
$row['url_media'] ?? '',
|
||||
$row['archivo'] ?? '',
|
||||
$row['fecha_hora'] ? date('d/m/Y H:i:s', strtotime($row['fecha_hora'])) : '',
|
||||
], ';');
|
||||
}
|
||||
|
||||
fclose($output);
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log('export_conversations.php error: ' . $e->getMessage());
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Content-Disposition: inline');
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Error al exportar conversaciones']);
|
||||
}
|
||||
@@ -32,6 +32,8 @@ try {
|
||||
c.created_at as last_message_time,
|
||||
c.status as last_message_status,
|
||||
u.advisor_requested as advisor_requested,
|
||||
u.terms_pending as terms_pending,
|
||||
u.terms_accepted_at as terms_accepted_at,
|
||||
COUNT(*) as total_conversations,
|
||||
SUM(CASE WHEN c.direction = 'incoming' AND c.status = 'received' THEN 1 ELSE 0 END) as unread_count
|
||||
FROM users u
|
||||
@@ -41,7 +43,7 @@ try {
|
||||
FROM conversations
|
||||
GROUP BY user_id
|
||||
)
|
||||
GROUP BY u.id, u.phone_number, u.name, c.content, c.direction, c.message_type, c.created_at, c.status, u.advisor_requested
|
||||
GROUP BY u.id, u.phone_number, u.name, c.content, c.direction, c.message_type, c.created_at, c.status, u.advisor_requested, u.terms_pending, u.terms_accepted_at
|
||||
ORDER BY c.created_at DESC
|
||||
LIMIT 50"
|
||||
);
|
||||
@@ -63,6 +65,8 @@ try {
|
||||
'last_message_time' => $conv['last_message_time'],
|
||||
'last_message_status' => $conv['last_message_status'] ?? 'sent',
|
||||
'advisor_requested' => !empty($conv['advisor_requested']) ? true : false,
|
||||
'terms_pending' => !empty($conv['terms_pending']) ? true : false,
|
||||
'terms_accepted_at' => $conv['terms_accepted_at'] ?? null,
|
||||
'total_conversations' => intval($conv['total_conversations']),
|
||||
'unread_count' => intval($conv['unread_count']),
|
||||
'time_ago' => timeAgo($conv['last_message_time'])
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
/**
|
||||
* GET api/get_terms_acceptances.php
|
||||
* Lista paginada de aceptaciones de T&C con stats y filtros.
|
||||
*
|
||||
* Query params:
|
||||
* estado = aceptado | rechazado | pendiente (opcional)
|
||||
* fecha = YYYY-MM-DD (filtra por fecha de envío, día completo)
|
||||
* phone = string parcial o completo del número
|
||||
* page = int (default 1)
|
||||
* per_page = int (default 50, máx 200)
|
||||
*/
|
||||
|
||||
session_start();
|
||||
require_once __DIR__ . '/../config/config.php';
|
||||
|
||||
requireAuthentication();
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
$pdo = $db->getConnection();
|
||||
|
||||
// ── Parámetros ────────────────────────────────────────────────────────
|
||||
$estado = in_array($_GET['estado'] ?? '', ['aceptado', 'rechazado', 'pendiente'])
|
||||
? $_GET['estado'] : null;
|
||||
$fecha = !empty($_GET['fecha']) && preg_match('/^\d{4}-\d{2}-\d{2}$/', $_GET['fecha'])
|
||||
? $_GET['fecha'] : null;
|
||||
$phone = isset($_GET['phone']) ? trim($_GET['phone']) : '';
|
||||
$page = max(1, (int)($_GET['page'] ?? 1));
|
||||
$perPage = min(200, max(1, (int)($_GET['per_page'] ?? 50)));
|
||||
$offset = ($page - 1) * $perPage;
|
||||
|
||||
// ── WHERE ─────────────────────────────────────────────────────────────
|
||||
$where = [];
|
||||
$params = [];
|
||||
|
||||
if ($estado !== null) {
|
||||
$where[] = "ta.estado COLLATE utf8mb4_unicode_ci = :estado";
|
||||
$params[':estado'] = $estado;
|
||||
}
|
||||
if ($fecha !== null) {
|
||||
$where[] = 'DATE(ta.fecha_envio) = :fecha';
|
||||
$params[':fecha'] = $fecha;
|
||||
}
|
||||
if ($phone !== '') {
|
||||
$where[] = "ta.phone_number COLLATE utf8mb4_unicode_ci LIKE :phone";
|
||||
$params[':phone'] = '%' . $phone . '%';
|
||||
}
|
||||
|
||||
$whereClause = $where ? 'WHERE ' . implode(' AND ', $where) : '';
|
||||
|
||||
// ── Stats (sin filtro de paginación) ──────────────────────────────────
|
||||
$statsSQL = "
|
||||
SELECT
|
||||
COALESCE(SUM(ta.estado COLLATE utf8mb4_unicode_ci = 'aceptado'), 0) AS aceptado,
|
||||
COALESCE(SUM(ta.estado COLLATE utf8mb4_unicode_ci = 'rechazado'), 0) AS rechazado,
|
||||
COALESCE(SUM(ta.estado COLLATE utf8mb4_unicode_ci = 'pendiente'), 0) AS pendiente,
|
||||
COUNT(*) AS total
|
||||
FROM terms_acceptance ta
|
||||
$whereClause
|
||||
";
|
||||
$stmtStats = $pdo->prepare($statsSQL);
|
||||
$stmtStats->execute($params);
|
||||
$statsRow = $stmtStats->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
$stats = [
|
||||
'aceptado' => (int)($statsRow['aceptado'] ?? 0),
|
||||
'rechazado' => (int)($statsRow['rechazado'] ?? 0),
|
||||
'pendiente' => (int)($statsRow['pendiente'] ?? 0),
|
||||
];
|
||||
$total = (int)($statsRow['total'] ?? 0);
|
||||
|
||||
// ── Datos paginados ───────────────────────────────────────────────────
|
||||
$dataSQL = "
|
||||
SELECT
|
||||
ta.id,
|
||||
ta.phone_number,
|
||||
u.name AS user_name,
|
||||
ta.estado,
|
||||
tv.version AS terms_version,
|
||||
ta.fecha_envio,
|
||||
ta.fecha_respuesta
|
||||
FROM terms_acceptance ta
|
||||
LEFT JOIN users u ON u.phone_number COLLATE utf8mb4_unicode_ci = ta.phone_number COLLATE utf8mb4_unicode_ci
|
||||
LEFT JOIN terms_versions tv ON tv.id = ta.terms_version_id
|
||||
$whereClause
|
||||
ORDER BY ta.fecha_envio DESC
|
||||
LIMIT :limit OFFSET :offset
|
||||
";
|
||||
|
||||
$stmtData = $pdo->prepare($dataSQL);
|
||||
foreach ($params as $k => $v) {
|
||||
$stmtData->bindValue($k, $v);
|
||||
}
|
||||
$stmtData->bindValue(':limit', $perPage, PDO::PARAM_INT);
|
||||
$stmtData->bindValue(':offset', $offset, PDO::PARAM_INT);
|
||||
$stmtData->execute();
|
||||
$rows = $stmtData->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'data' => $rows,
|
||||
'stats' => $stats,
|
||||
'total' => $total,
|
||||
'page' => $page,
|
||||
'pages' => (int)ceil($total / $perPage),
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
|
||||
} catch (Exception $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* API - Obtener configuración de Términos y Condiciones
|
||||
*/
|
||||
|
||||
require_once '../config/config.php';
|
||||
|
||||
error_reporting(E_ALL);
|
||||
@ini_set('display_errors', 0);
|
||||
|
||||
requireAuthentication();
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
$active = $db->fetch(
|
||||
"SELECT id, version, documento_url, documento_nombre, mensaje_aceptacion,
|
||||
mensaje_rechazo, forzar_reenvio, activa, created_at
|
||||
FROM terms_versions
|
||||
WHERE activa = 1
|
||||
ORDER BY id DESC LIMIT 1"
|
||||
);
|
||||
|
||||
echo json_encode(['success' => true, 'data' => $active ?: null]);
|
||||
} catch (Exception $e) {
|
||||
error_log('get_terms_config.php error: ' . $e->getMessage());
|
||||
http_response_code(500);
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
/**
|
||||
* Helpers compartidos para los endpoints del módulo de laboratorio.
|
||||
* Incluido automáticamente por cada endpoint de /api/lab/.
|
||||
*/
|
||||
|
||||
// Capturar cualquier salida accidental (warnings, notices) antes del JSON
|
||||
ob_start();
|
||||
|
||||
require_once __DIR__ . '/../../config/config.php';
|
||||
require_once __DIR__ . '/../../classes/lab/ActividadAdmin.php';
|
||||
require_once __DIR__ . '/../../classes/lab/Paciente.php';
|
||||
require_once __DIR__ . '/../../classes/lab/Enfermera.php';
|
||||
require_once __DIR__ . '/../../classes/lab/OrdenMedica.php';
|
||||
require_once __DIR__ . '/../../classes/lab/Domicilio.php';
|
||||
require_once __DIR__ . '/../../classes/lab/Asignacion.php';
|
||||
require_once __DIR__ . '/../../classes/lab/Formulario.php';
|
||||
|
||||
// Los endpoints API nunca deben mostrar errores PHP en HTML — enviar como JSON
|
||||
error_reporting(E_ERROR | E_PARSE);
|
||||
ini_set('display_errors', '0');
|
||||
ini_set('html_errors', '0');
|
||||
|
||||
// Interceptar errores fatales y devolverlos como JSON en lugar de HTML
|
||||
register_shutdown_function(function () {
|
||||
$err = error_get_last();
|
||||
if ($err && in_array($err['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
|
||||
ob_clean();
|
||||
http_response_code(500);
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
echo json_encode([
|
||||
'ok' => false,
|
||||
'error' => 'Error interno del servidor: ' . $err['message'],
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
// Cabeceras JSON estándar
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
|
||||
header('Access-Control-Allow-Headers: Content-Type');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||
http_response_code(204);
|
||||
exit;
|
||||
}
|
||||
|
||||
requireAuthentication();
|
||||
|
||||
/**
|
||||
* ID del admin autenticado actualmente.
|
||||
*/
|
||||
function adminId(): ?int {
|
||||
return isset($_SESSION['admin_user']['id'])
|
||||
? (int)$_SESSION['admin_user']['id']
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rol del usuario autenticado ('admin' | 'enfermero').
|
||||
*/
|
||||
function userRole(): string {
|
||||
return $_SESSION['admin_user']['role'] ?? 'admin';
|
||||
}
|
||||
|
||||
/**
|
||||
* Detiene la ejecución con 403 JSON si el usuario no es admin (bloquea enfermeros).
|
||||
*/
|
||||
function requireAdmin(): void {
|
||||
if (userRole() !== 'admin') {
|
||||
jsonError('Acceso restringido a administradores', 403);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detiene la ejecución si no se puede actuar como enfermero.
|
||||
* Acepta tanto admins (que pueden actuar en nombre de cualquier enfermera)
|
||||
* como el propio enfermero autenticado.
|
||||
*/
|
||||
function requireEnfermeroAccess(int $enfermeraIdSolicitado): void {
|
||||
if (userRole() === 'admin') return;
|
||||
$propio = enfermeraId();
|
||||
if (!$propio || $propio !== $enfermeraIdSolicitado) {
|
||||
jsonError('Solo puedes gestionar tus propios domicilios', 403);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lee el body JSON del request.
|
||||
*/
|
||||
function inputJson(): array {
|
||||
static $parsed = null;
|
||||
if ($parsed === null) {
|
||||
$raw = file_get_contents('php://input');
|
||||
$parsed = json_decode($raw, true) ?? [];
|
||||
}
|
||||
return $parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Devuelve una respuesta de éxito.
|
||||
*/
|
||||
function jsonOk(array $payload = [], string $mensaje = ''): void {
|
||||
ob_clean();
|
||||
$resp = ['ok' => true, 'success' => true];
|
||||
if ($mensaje) {
|
||||
$resp['message'] = $mensaje;
|
||||
}
|
||||
echo json_encode(array_merge($resp, $payload), JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Devuelve un error JSON con código HTTP.
|
||||
*/
|
||||
function jsonError(string $mensaje, int $code = 400): void {
|
||||
ob_clean();
|
||||
http_response_code($code);
|
||||
echo json_encode(['ok' => false, 'success' => false, 'error' => $mensaje], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Valida que el método HTTP sea el esperado.
|
||||
*/
|
||||
function requireMethod(string $method): void {
|
||||
if ($_SERVER['REQUEST_METHOD'] !== strtoupper($method)) {
|
||||
jsonError('Método no permitido', 405);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/**
|
||||
* POST /api/lab/autorizar_orden.php
|
||||
* Cambia el estado de una orden médica (flujo de revisión).
|
||||
* Body JSON:
|
||||
* { id, accion: 'en_revision'|'autorizada'|'rechazada'|'completada', comentario? }
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('POST');
|
||||
|
||||
try {
|
||||
$datos = inputJson();
|
||||
$om = new OrdenMedica();
|
||||
$admin = adminId();
|
||||
|
||||
if (empty($datos['id'])) {
|
||||
jsonError('El campo id es obligatorio');
|
||||
}
|
||||
if (empty($datos['accion'])) {
|
||||
jsonError('El campo accion es obligatorio');
|
||||
}
|
||||
|
||||
$id = (int)$datos['id'];
|
||||
$accion = $datos['accion'];
|
||||
$comentario = $datos['comentario'] ?? '';
|
||||
|
||||
if ($accion === 'rechazada' && empty($comentario)) {
|
||||
jsonError('El motivo de rechazo es obligatorio');
|
||||
}
|
||||
|
||||
$om->cambiarEstado($id, $accion, $admin, $comentario);
|
||||
|
||||
$mensajes = [
|
||||
'en_revision' => 'Orden marcada en revisión',
|
||||
'autorizada' => 'Orden autorizada correctamente',
|
||||
'rechazada' => 'Orden rechazada',
|
||||
'en_domicilio'=> 'Orden marcada como en domicilio',
|
||||
'completada' => 'Orden completada',
|
||||
];
|
||||
|
||||
jsonOk(['id' => $id], $mensajes[$accion] ?? 'Estado actualizado');
|
||||
} catch (InvalidArgumentException $e) {
|
||||
jsonError($e->getMessage());
|
||||
} catch (Exception $e) {
|
||||
jsonError($e->getMessage(), 500);
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
/**
|
||||
* API: Crear orden médica desde conversación de WhatsApp
|
||||
*
|
||||
* GET ?solo_paciente=1&conversation_id=X → obtiene/crea paciente del contacto
|
||||
* POST { paciente_id, conversation_id, local_file, media_message_id, ... }
|
||||
* → crea lab_ordenes_medicas
|
||||
*/
|
||||
require_once __DIR__ . '/../../config/config.php';
|
||||
require_once __DIR__ . '/../../classes/Database.php';
|
||||
require_once __DIR__ . '/../../classes/lab/ActividadAdmin.php';
|
||||
require_once __DIR__ . '/../../classes/lab/Paciente.php';
|
||||
require_once __DIR__ . '/../../classes/lab/OrdenMedica.php';
|
||||
|
||||
// Helpers inline (similar a _helpers.php pero sin incluir todas las clases de nuevo)
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('X-Content-Type-Options: nosniff');
|
||||
|
||||
requireAuthentication();
|
||||
|
||||
$adminId = (int)($_SESSION['admin_user']['id'] ?? 0);
|
||||
$db = Database::getInstance();
|
||||
|
||||
// ── GET: solo_paciente ─────────────────────────────────────────────────────
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['solo_paciente'])) {
|
||||
$convId = (int)($_GET['conversation_id'] ?? 0);
|
||||
$userId = (int)($_GET['user_id'] ?? 0);
|
||||
|
||||
if (!$convId && !$userId) {
|
||||
echo json_encode(['success' => false, 'error' => 'conversation_id o user_id requerido']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Obtener user_id y phone_number: por conversation_id o directamente por user_id
|
||||
if ($convId) {
|
||||
$conv = $db->fetch(
|
||||
'SELECT c.id, c.user_id, u.phone_number, u.name AS whatsapp_name
|
||||
FROM conversations c
|
||||
JOIN users u ON u.id = c.user_id
|
||||
WHERE c.id = ?',
|
||||
[$convId]
|
||||
);
|
||||
} else {
|
||||
$conv = $db->fetch(
|
||||
'SELECT u.id AS user_id, u.phone_number, u.name AS whatsapp_name
|
||||
FROM users u
|
||||
WHERE u.id = ?',
|
||||
[$userId]
|
||||
);
|
||||
}
|
||||
|
||||
if (!$conv) {
|
||||
echo json_encode(['success' => false, 'error' => 'Conversación / usuario no encontrado']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$pacienteRepo = new Paciente();
|
||||
$pacienteId = $pacienteRepo->obtenerOCrearDesdeWhatsapp($conv['user_id']);
|
||||
$paciente = $pacienteRepo->obtener($pacienteId);
|
||||
echo json_encode(['success' => true, 'paciente' => $paciente]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// ── POST: crear orden ──────────────────────────────────────────────────────
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
echo json_encode(['success' => false, 'error' => 'Método no permitido']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
if (!$input) {
|
||||
echo json_encode(['success' => false, 'error' => 'Datos inválidos']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$pacienteId = (int)($input['paciente_id'] ?? 0);
|
||||
if (!$pacienteId) {
|
||||
echo json_encode(['success' => false, 'error' => 'paciente_id requerido']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Construir datos de la orden
|
||||
$datos = [
|
||||
'paciente_id' => $pacienteId,
|
||||
'conversation_id' => !empty($input['conversation_id']) ? (int)$input['conversation_id'] : null,
|
||||
'local_file' => $input['local_file'] ?? null,
|
||||
'media_message_id' => $input['media_message_id'] ?? null,
|
||||
'medico_nombre' => $input['medico_nombre'] ?? null,
|
||||
'fecha_orden' => !empty($input['fecha_orden']) ? $input['fecha_orden'] : null,
|
||||
'examenes_solicitados'=> $input['examenes_solicitados']?? null,
|
||||
'requiere_ayuno' => isset($input['requiere_ayuno']) ? (int)$input['requiere_ayuno'] : 0,
|
||||
'horas_ayuno' => !empty($input['horas_ayuno']) ? (int)$input['horas_ayuno'] : null,
|
||||
'notas_admin' => $input['notas_admin'] ?? null,
|
||||
'estado' => 'pendiente',
|
||||
];
|
||||
|
||||
try {
|
||||
$orden = new OrdenMedica();
|
||||
$ordenId = $orden->crear($datos, $adminId);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'orden_id' => $ordenId,
|
||||
'message' => "Orden médica #$ordenId creada correctamente",
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
error_log('[lab/crear_desde_whatsapp] ' . $e->getMessage());
|
||||
echo json_encode(['success' => false, 'error' => 'Error interno: ' . $e->getMessage()]);
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
/**
|
||||
* POST /api/lab/create_enfermero_user.php
|
||||
* Crea o actualiza el usuario de acceso al sistema para una enfermera.
|
||||
* Solo administradores pueden llamar este endpoint.
|
||||
*
|
||||
* Body JSON:
|
||||
* { enfermera_id, username, password?, full_name? }
|
||||
* Si el usuario ya existe para esa enfermera_id, actualiza username/password.
|
||||
* Si password viene vacío en actualización, no cambia la contraseña.
|
||||
*
|
||||
* Returns:
|
||||
* { ok:true, message, user_id }
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireAdmin();
|
||||
requireMethod('POST');
|
||||
|
||||
try {
|
||||
$datos = inputJson();
|
||||
$enfermeraId = (int)($datos['enfermera_id'] ?? 0);
|
||||
$username = trim($datos['username'] ?? '');
|
||||
$password = $datos['password'] ?? '';
|
||||
$fullName = trim($datos['full_name'] ?? '');
|
||||
|
||||
if (!$enfermeraId) jsonError('enfermera_id es obligatorio');
|
||||
if (!$username) jsonError('username es obligatorio');
|
||||
if (strlen($username) < 3) jsonError('El usuario debe tener al menos 3 caracteres');
|
||||
|
||||
$db = Database::getInstance();
|
||||
|
||||
// Verificar que la enfermera existe
|
||||
$enf = $db->fetch('SELECT id, nombre_completo FROM lab_enfermeras WHERE id = ?', [$enfermeraId]);
|
||||
if (!$enf) jsonError('Enfermera no encontrada', 404);
|
||||
|
||||
if (empty($fullName)) $fullName = $enf['nombre_completo'];
|
||||
|
||||
// ¿Ya existe un usuario vinculado a esta enfermera?
|
||||
$existente = $db->fetch(
|
||||
'SELECT id, username FROM admin_users WHERE enfermera_id = ? LIMIT 1',
|
||||
[$enfermeraId]
|
||||
);
|
||||
|
||||
if ($existente) {
|
||||
// --- ACTUALIZAR ---
|
||||
// Verificar que el nuevo username no esté en uso por OTRO usuario
|
||||
$conflicto = $db->fetch(
|
||||
'SELECT id FROM admin_users WHERE username = ? AND id != ?',
|
||||
[$username, $existente['id']]
|
||||
);
|
||||
if ($conflicto) jsonError("El usuario '$username' ya está en uso por otra cuenta");
|
||||
|
||||
$sets = ['username = ?', 'full_name = ?', 'is_active = 1', 'updated_at = NOW()'];
|
||||
$vals = [$username, $fullName];
|
||||
|
||||
if (!empty($password)) {
|
||||
if (strlen($password) < 6) jsonError('La contraseña debe tener al menos 6 caracteres');
|
||||
$sets[] = 'password_hash = ?';
|
||||
$vals[] = password_hash($password, PASSWORD_DEFAULT);
|
||||
}
|
||||
|
||||
$vals[] = $existente['id'];
|
||||
$db->execute(
|
||||
'UPDATE admin_users SET ' . implode(', ', $sets) . ' WHERE id = ?',
|
||||
$vals
|
||||
);
|
||||
|
||||
jsonOk(['user_id' => $existente['id']], 'Acceso actualizado correctamente');
|
||||
|
||||
} else {
|
||||
// --- CREAR ---
|
||||
if (empty($password)) jsonError('La contraseña es obligatoria para crear el acceso');
|
||||
if (strlen($password) < 6) jsonError('La contraseña debe tener al menos 6 caracteres');
|
||||
|
||||
// Verificar username único
|
||||
$conflicto = $db->fetch('SELECT id FROM admin_users WHERE username = ?', [$username]);
|
||||
if ($conflicto) jsonError("El usuario '$username' ya está en uso");
|
||||
|
||||
$hash = password_hash($password, PASSWORD_DEFAULT);
|
||||
$db->execute(
|
||||
"INSERT INTO admin_users (username, password_hash, full_name, role, enfermera_id, is_active, created_at)
|
||||
VALUES (?, ?, ?, 'enfermero', ?, 1, NOW())",
|
||||
[$username, $hash, $fullName, $enfermeraId]
|
||||
);
|
||||
$userId = $db->lastInsertId();
|
||||
|
||||
jsonOk(['user_id' => $userId], 'Acceso creado correctamente');
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
jsonError($e->getMessage(), 500);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* POST /api/lab/delete_lab_user.php
|
||||
* Elimina un usuario. No permite auto-eliminarse.
|
||||
* Solo admins.
|
||||
*
|
||||
* Body JSON: { id }
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('POST');
|
||||
requireAdmin();
|
||||
|
||||
$body = inputJson();
|
||||
$id = (int)($body['id'] ?? 0);
|
||||
if (!$id) jsonError('ID de usuario requerido');
|
||||
|
||||
$selfId = adminId();
|
||||
if ($id === $selfId) jsonError('No puedes eliminar tu propio usuario');
|
||||
|
||||
$db = Database::getInstance();
|
||||
$user = $db->fetch("SELECT id, username FROM admin_users WHERE id = ?", [$id]);
|
||||
if (!$user) jsonError('Usuario no encontrado', 404);
|
||||
|
||||
$db->query("DELETE FROM admin_users WHERE id = ?", [$id]);
|
||||
|
||||
jsonOk([], "Usuario '{$user['username']}' eliminado correctamente");
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/**
|
||||
* POST /api/lab/delete_role.php
|
||||
* Elimina un rol no-sistema.
|
||||
* Solo admins.
|
||||
*
|
||||
* Body JSON: { id }
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('POST');
|
||||
requireAdmin();
|
||||
|
||||
$body = inputJson();
|
||||
$id = (int)($body['id'] ?? 0);
|
||||
if (!$id) jsonError('ID de rol requerido');
|
||||
|
||||
$db = Database::getInstance();
|
||||
$role = $db->fetch("SELECT id, is_system, slug FROM roles WHERE id = ?", [$id]);
|
||||
if (!$role) jsonError('Rol no encontrado', 404);
|
||||
if ($role['is_system']) jsonError('Los roles del sistema no se pueden eliminar');
|
||||
|
||||
// Reasignar usuarios que tengan este rol al rol admin (id=1) antes de borrar
|
||||
$db->query("UPDATE admin_users SET role_id = 1, role = 'admin' WHERE role_id = ?", [$id]);
|
||||
|
||||
// La FK ON DELETE CASCADE borra role_modules automáticamente
|
||||
$db->query("DELETE FROM roles WHERE id = ?", [$id]);
|
||||
|
||||
jsonOk([], 'Rol eliminado. Los usuarios afectados fueron reasignados al rol Administrador.');
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/** GET /api/lab/get_actividad.php — Log de trazabilidad del módulo */
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('GET');
|
||||
|
||||
try {
|
||||
$log = new ActividadAdmin();
|
||||
|
||||
$modulo = $_GET['modulo'] ?? '';
|
||||
$adminFilt = (int)($_GET['admin_id'] ?? 0);
|
||||
$entidad = (int)($_GET['entidad_id'] ?? 0);
|
||||
$limit = max(1, min(200, (int)($_GET['limit'] ?? 50)));
|
||||
|
||||
if ($adminFilt) {
|
||||
$data = $log->porAdmin($adminFilt, $limit);
|
||||
} elseif ($entidad && $modulo) {
|
||||
$data = $log->porEntidad($modulo, $entidad);
|
||||
} else {
|
||||
$data = $log->reciente($limit, $modulo);
|
||||
}
|
||||
|
||||
jsonOk(['data' => $data, 'total' => count($data)]);
|
||||
} catch (Exception $e) {
|
||||
jsonError($e->getMessage(), 500);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
/** GET /api/lab/get_asignaciones.php — Asignaciones del día / por enfermera */
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('GET');
|
||||
|
||||
try {
|
||||
$asig = new Asignacion();
|
||||
|
||||
$fecha = $_GET['fecha'] ?? date('Y-m-d');
|
||||
$data = $asig->porFecha($fecha);
|
||||
$carga = $asig->cargaHoy();
|
||||
|
||||
jsonOk([
|
||||
'data' => $data,
|
||||
'total' => count($data),
|
||||
'fecha' => $fecha,
|
||||
'carga_hoy' => $carga,
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
jsonError($e->getMessage(), 500);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* GET /api/lab/get_config.php — config global del lab
|
||||
* GET /api/lab/get_config.php?forma=1 — config como objeto clave=>valor (para el builder)
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('GET');
|
||||
|
||||
$db = Database::getInstance();
|
||||
$rows = $db->fetchAll('SELECT clave, valor FROM lab_config ORDER BY clave');
|
||||
|
||||
$cfg = [];
|
||||
foreach ($rows as $r) {
|
||||
$cfg[$r['clave']] = $r['valor'];
|
||||
}
|
||||
|
||||
jsonOk(['config' => $cfg]);
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/** GET /api/lab/get_domicilios.php — Lista de domicilios con filtros */
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('GET');
|
||||
|
||||
try {
|
||||
$dom = new Domicilio();
|
||||
|
||||
// Vista de un solo domicilio
|
||||
if (!empty($_GET['id'])) {
|
||||
$d = $dom->obtener((int)$_GET['id']);
|
||||
if (!$d) {
|
||||
jsonError('Domicilio no encontrado', 404);
|
||||
}
|
||||
jsonOk(['domicilio' => $d]);
|
||||
}
|
||||
|
||||
$filtros = array_filter([
|
||||
'fecha' => $_GET['fecha'] ?? '',
|
||||
'desde' => $_GET['desde'] ?? '',
|
||||
'hasta' => $_GET['hasta'] ?? '',
|
||||
'estado' => $_GET['estado'] ?? '',
|
||||
'enfermera_id' => (int)($_GET['enfermera_id'] ?? 0) ?: null,
|
||||
'paciente_id' => (int)($_GET['paciente_id'] ?? 0) ?: null,
|
||||
], fn($v) => $v !== null && $v !== '');
|
||||
|
||||
$pagina = max(1, (int)($_GET['page'] ?? 1));
|
||||
$por = max(1, min(200, (int)($_GET['limit'] ?? 30)));
|
||||
|
||||
$resultado = $dom->listar($filtros, $pagina, $por);
|
||||
|
||||
// Incluir resumen del día
|
||||
if (empty($_GET['no_stats'])) {
|
||||
$resultado['estadisticas_hoy'] = $dom->estadisticasHoy();
|
||||
$resultado['sin_asignar_hoy'] = count($dom->sinAsignar());
|
||||
}
|
||||
|
||||
jsonOk($resultado);
|
||||
} catch (Exception $e) {
|
||||
jsonError($e->getMessage(), 500);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/** GET /api/lab/get_enfermeras.php — Lista de enfermeras */
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('GET');
|
||||
|
||||
try {
|
||||
$enf = new Enfermera();
|
||||
|
||||
// Perfil + agenda de una sola enfermera
|
||||
if (!empty($_GET['id'])) {
|
||||
$id = (int)$_GET['id'];
|
||||
$e = $enf->obtener($id);
|
||||
if (!$e) {
|
||||
jsonError('Enfermera no encontrada', 404);
|
||||
}
|
||||
$fecha = $_GET['fecha'] ?? date('Y-m-d');
|
||||
$e['agenda'] = $enf->agenda($id, $fecha);
|
||||
|
||||
// Incluir info de acceso al sistema (si tiene usuario creado)
|
||||
$db = Database::getInstance();
|
||||
$u = $db->fetch(
|
||||
'SELECT id, username FROM admin_users WHERE enfermera_id = ? AND role = "enfermero" LIMIT 1',
|
||||
[$id]
|
||||
);
|
||||
$e['usuario_acceso'] = $u ?: null;
|
||||
|
||||
jsonOk(['enfermera' => $e]);
|
||||
}
|
||||
|
||||
$soloActivas = !isset($_GET['todas']) || $_GET['todas'] !== '1';
|
||||
$lista = $enf->listar($soloActivas);
|
||||
|
||||
// Enriquecer con username de acceso para cada enfermera
|
||||
$db = Database::getInstance();
|
||||
foreach ($lista as &$item) {
|
||||
$u = $db->fetch(
|
||||
'SELECT username FROM admin_users WHERE enfermera_id = ? AND is_active = 1 LIMIT 1',
|
||||
[$item['id']]
|
||||
);
|
||||
$item['username_acceso'] = $u['username'] ?? null;
|
||||
}
|
||||
unset($item);
|
||||
|
||||
jsonOk(['data' => $lista, 'total' => count($lista)]);
|
||||
} catch (Exception $e) {
|
||||
jsonError($e->getMessage(), 500);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
* GET /api/lab/get_formularios.php — Lista de plantillas
|
||||
* GET /api/lab/get_formularios.php?id=X — Plantilla específica
|
||||
* GET /api/lab/get_formularios.php?envios=1&formulario_id=X — Envíos
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('GET');
|
||||
|
||||
try {
|
||||
$form = new Formulario();
|
||||
|
||||
// Lista de envíos
|
||||
if (!empty($_GET['envios'])) {
|
||||
$filtros = [];
|
||||
if (!empty($_GET['formulario_id'])) $filtros['formulario_id'] = (int)$_GET['formulario_id'];
|
||||
if (!empty($_GET['paciente_id'])) $filtros['paciente_id'] = (int)$_GET['paciente_id'];
|
||||
if (!empty($_GET['estado'])) $filtros['estado'] = $_GET['estado'];
|
||||
// Enfermero solo ve los suyos
|
||||
if (userRole() === 'enfermero') {
|
||||
$filtros['enviado_por'] = adminId();
|
||||
}
|
||||
jsonOk(['data' => $form->listarEnvios($filtros)]);
|
||||
}
|
||||
|
||||
// Plantilla específica
|
||||
if (!empty($_GET['id'])) {
|
||||
$f = $form->obtener((int)$_GET['id']);
|
||||
if (!$f) jsonError('Formulario no encontrado', 404);
|
||||
jsonOk(['formulario' => $f]);
|
||||
}
|
||||
|
||||
// Lista de plantillas
|
||||
$todas = isset($_GET['todas']) && userRole() === 'admin';
|
||||
jsonOk(['data' => $form->listar(!$todas)]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
jsonError($e->getMessage(), 500);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/**
|
||||
* GET /api/lab/get_lab_users.php
|
||||
* Devuelve todos los usuarios del sistema con información de rol.
|
||||
* Solo admins.
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireAdmin();
|
||||
|
||||
$db = Database::getInstance();
|
||||
|
||||
$users = $db->fetchAll("
|
||||
SELECT
|
||||
u.id,
|
||||
u.username,
|
||||
u.full_name,
|
||||
u.email,
|
||||
u.is_active,
|
||||
u.role,
|
||||
u.role_id,
|
||||
u.enfermera_id,
|
||||
u.last_login,
|
||||
u.created_at,
|
||||
r.name AS role_name,
|
||||
r.color AS role_color,
|
||||
r.slug AS role_slug,
|
||||
e.nombre_completo AS enfermera_nombre
|
||||
FROM admin_users u
|
||||
LEFT JOIN roles r ON r.id = u.role_id
|
||||
LEFT JOIN lab_enfermeras e ON e.id = u.enfermera_id
|
||||
ORDER BY u.id ASC
|
||||
");
|
||||
|
||||
foreach ($users as &$u) {
|
||||
$u['is_active'] = (bool)$u['is_active'];
|
||||
$u['role_name'] = $u['role_name'] ?? ucfirst($u['role'] ?? 'admin');
|
||||
$u['role_color'] = $u['role_color'] ?? '#0d6efd';
|
||||
}
|
||||
unset($u);
|
||||
|
||||
jsonOk(['users' => $users]);
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/** GET /api/lab/get_ordenes.php — Lista paginada de órdenes médicas con filtros */
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('GET');
|
||||
|
||||
try {
|
||||
$om = new OrdenMedica();
|
||||
|
||||
$filtros = array_filter([
|
||||
'estado' => $_GET['estado'] ?? '',
|
||||
'paciente_id' => (int)($_GET['paciente_id'] ?? 0) ?: null,
|
||||
'desde' => $_GET['desde'] ?? '',
|
||||
'hasta' => $_GET['hasta'] ?? '',
|
||||
'busqueda' => trim($_GET['busqueda'] ?? $_GET['search'] ?? ''),
|
||||
], fn($v) => $v !== null && $v !== '');
|
||||
|
||||
$pagina = max(1, (int)($_GET['page'] ?? 1));
|
||||
$por = max(1, min(100, (int)($_GET['limit'] ?? 30)));
|
||||
|
||||
// Vista de una sola orden
|
||||
if (!empty($_GET['id'])) {
|
||||
$orden = $om->obtener((int)$_GET['id']);
|
||||
if (!$orden) {
|
||||
jsonError('Orden no encontrada', 404);
|
||||
}
|
||||
jsonOk(['orden' => $orden]);
|
||||
}
|
||||
|
||||
$resultado = $om->listar($filtros, $pagina, $por);
|
||||
|
||||
// Incluir también el contador por estado para el dashboard
|
||||
if (!isset($_GET['no_counts'])) {
|
||||
$resultado['contadores'] = $om->contadorPorEstado();
|
||||
}
|
||||
|
||||
jsonOk($resultado);
|
||||
} catch (Exception $e) {
|
||||
jsonError($e->getMessage(), 500);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
/** GET /api/lab/get_pacientes.php — Lista paginada de pacientes */
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('GET');
|
||||
|
||||
try {
|
||||
$pac = new Paciente();
|
||||
|
||||
$busqueda = trim($_GET['busqueda'] ?? $_GET['search'] ?? '');
|
||||
$pagina = max(1, (int)($_GET['page'] ?? $_GET['pagina'] ?? 1));
|
||||
$por = max(1, min(100, (int)($_GET['limit'] ?? $_GET['por_pagina'] ?? 30)));
|
||||
|
||||
jsonOk($pac->listar($busqueda, $pagina, $por));
|
||||
} catch (Exception $e) {
|
||||
jsonError($e->getMessage(), 500);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/**
|
||||
* GET /api/lab/get_roles.php
|
||||
* Devuelve todos los roles con sus módulos asignados.
|
||||
* Solo admins.
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireAdmin();
|
||||
|
||||
$db = Database::getInstance();
|
||||
|
||||
$roles = $db->fetchAll("SELECT id, name, slug, description, color, is_system, created_at FROM roles ORDER BY id ASC");
|
||||
|
||||
foreach ($roles as &$role) {
|
||||
$mods = $db->fetchAll(
|
||||
"SELECT module_slug FROM role_modules WHERE role_id = ? ORDER BY module_slug",
|
||||
[$role['id']]
|
||||
);
|
||||
$role['modules'] = array_column($mods, 'module_slug');
|
||||
$role['is_system'] = (bool)$role['is_system'];
|
||||
$role['user_count'] = (int)$db->fetch(
|
||||
"SELECT COUNT(*) AS c FROM admin_users WHERE role_id = ?",
|
||||
[$role['id']]
|
||||
)['c'];
|
||||
}
|
||||
unset($role);
|
||||
|
||||
jsonOk(['roles' => $roles]);
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/**
|
||||
* GET /api/lab/get_stats.php — Estadísticas del dashboard del módulo
|
||||
* Devuelve contadores, pendientes urgentes, agenda hoy y carga de enfermeras.
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('GET');
|
||||
|
||||
try {
|
||||
$om = new OrdenMedica();
|
||||
$dom = new Domicilio();
|
||||
$asig = new Asignacion();
|
||||
$pac = new Paciente();
|
||||
$db = Database::getInstance();
|
||||
|
||||
// ── Órdenes ──────────────────────────────────────────────────────────────
|
||||
$estadosOrdenes = $om->contadorPorEstado();
|
||||
$pendientesViejos = $om->pendientesAntiguos(5);
|
||||
|
||||
// ── Domicilios hoy ───────────────────────────────────────────────────────
|
||||
$estDomHoy = $dom->estadisticasHoy();
|
||||
$sinAsignarHoy = $dom->sinAsignar();
|
||||
|
||||
// ── Carga de enfermeras hoy ──────────────────────────────────────────────
|
||||
$cargaEnfermeras = $asig->cargaHoy();
|
||||
|
||||
// ── Totales generales ────────────────────────────────────────────────────
|
||||
$totalPacientes = $db->fetch('SELECT COUNT(*) AS n FROM lab_pacientes WHERE is_active = 1')['n'] ?? 0;
|
||||
$totalEnfermeras = $db->fetch('SELECT COUNT(*) AS n FROM lab_enfermeras WHERE is_active = 1')['n'] ?? 0;
|
||||
|
||||
// ── Órdenes de hoy ───────────────────────────────────────────────────────
|
||||
$ordenesHoy = $db->fetch(
|
||||
'SELECT COUNT(*) AS n FROM lab_ordenes_medicas WHERE DATE(created_at) = CURDATE()'
|
||||
)['n'] ?? 0;
|
||||
|
||||
// ── Actividad reciente ───────────────────────────────────────────────────
|
||||
$actividadReciente = (new ActividadAdmin())->reciente(10);
|
||||
|
||||
jsonOk([
|
||||
'ordenes' => [
|
||||
'por_estado' => $estadosOrdenes,
|
||||
'pendientes_hoy' => (int)($estadosOrdenes['pendiente'] ?? 0),
|
||||
'en_revision_hoy' => (int)($estadosOrdenes['en_revision'] ?? 0),
|
||||
'pendientes_viejos'=> $pendientesViejos,
|
||||
'total_hoy' => (int)$ordenesHoy,
|
||||
],
|
||||
'domicilios' => [
|
||||
'por_estado' => $estDomHoy,
|
||||
'total_hoy' => array_sum($estDomHoy),
|
||||
'sin_asignar' => count($sinAsignarHoy),
|
||||
'lista_sin_asignar' => $sinAsignarHoy,
|
||||
],
|
||||
'enfermeras' => [
|
||||
'activas' => (int)$totalEnfermeras,
|
||||
'carga_hoy' => $cargaEnfermeras,
|
||||
],
|
||||
'generales' => [
|
||||
'total_pacientes' => (int)$totalPacientes,
|
||||
],
|
||||
'actividad_reciente' => $actividadReciente,
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
jsonError($e->getMessage(), 500);
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/**
|
||||
* GET /api/lab/my_agenda.php
|
||||
* Devuelve la agenda del enfermero autenticado (o de cualquier enfermera para admins).
|
||||
*
|
||||
* Query params:
|
||||
* enfermera_id (int) — Requerido para admins. Enfermeros usan automáticamente el suyo.
|
||||
* fecha (Y-m-d) — Por defecto: hoy.
|
||||
* rango_inicio (Y-m-d) — Para vista semanal/mensual.
|
||||
* rango_fin (Y-m-d)
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('GET');
|
||||
|
||||
try {
|
||||
// Determinar enfermera_id
|
||||
if (userRole() === 'enfermero') {
|
||||
$eid = enfermeraId();
|
||||
if (!$eid) {
|
||||
jsonError('Tu usuario no tiene una enfermera vinculada. Contacta al administrador.');
|
||||
}
|
||||
} else {
|
||||
$eid = (int)($_GET['enfermera_id'] ?? 0);
|
||||
if (!$eid) {
|
||||
jsonError('enfermera_id requerido');
|
||||
}
|
||||
}
|
||||
|
||||
$enf = new Enfermera();
|
||||
$fecha = $_GET['fecha'] ?? date('Y-m-d');
|
||||
|
||||
// Agenda del día con pleno detalle
|
||||
$agenda = $enf->agenda($eid, $fecha);
|
||||
|
||||
// Enriquecer con servicios extra y estado de asignación
|
||||
$db = Database::getInstance();
|
||||
foreach ($agenda as &$item) {
|
||||
$item['servicios_extra'] = $db->fetchAll(
|
||||
"SELECT * FROM lab_servicios_extra WHERE domicilio_id = ? ORDER BY created_at ASC",
|
||||
[(int)$item['domicilio_id']]
|
||||
);
|
||||
// Info completa del domicilio (notas, indicaciones)
|
||||
$extra = $db->fetch(
|
||||
"SELECT notas_admin, indicaciones_dir, barrio, ciudad FROM lab_domicilios WHERE id = ?",
|
||||
[(int)$item['domicilio_id']]
|
||||
);
|
||||
if ($extra) $item = array_merge($item, $extra);
|
||||
}
|
||||
unset($item);
|
||||
|
||||
// Resumen rápido
|
||||
$totales = array_count_values(array_column($agenda, 'domicilio_estado'));
|
||||
|
||||
jsonOk([
|
||||
'enfermera_id' => $eid,
|
||||
'fecha' => $fecha,
|
||||
'agenda' => $agenda,
|
||||
'total' => count($agenda),
|
||||
'totales' => $totales,
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
jsonError($e->getMessage(), 500);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/**
|
||||
* POST /api/lab/save_asignacion.php
|
||||
* Asigna (o reasigna) una enfermera a un domicilio.
|
||||
* Body JSON:
|
||||
* { domicilio_id, enfermera_id, notas? }
|
||||
* -- Para liberar/completar:
|
||||
* { id, accion: 'liberar'|'completar', motivo? }
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('POST');
|
||||
|
||||
try {
|
||||
$datos = inputJson();
|
||||
$asig = new Asignacion();
|
||||
$admin = adminId();
|
||||
|
||||
// Liberar o completar
|
||||
if (!empty($datos['id']) && !empty($datos['accion'])) {
|
||||
$id = (int)$datos['id'];
|
||||
if ($datos['accion'] === 'liberar') {
|
||||
$asig->liberar($id, $admin, $datos['motivo'] ?? '');
|
||||
jsonOk(['id' => $id], 'Asignación liberada');
|
||||
}
|
||||
if ($datos['accion'] === 'completar') {
|
||||
$asig->completar($id, $admin);
|
||||
jsonOk(['id' => $id], 'Asignación completada');
|
||||
}
|
||||
jsonError('Acción no reconocida');
|
||||
}
|
||||
|
||||
// Asignar / reasignar
|
||||
foreach (['domicilio_id', 'enfermera_id'] as $req) {
|
||||
if (empty($datos[$req])) {
|
||||
jsonError("El campo $req es obligatorio");
|
||||
}
|
||||
}
|
||||
|
||||
$id = $asig->asignar(
|
||||
(int)$datos['domicilio_id'],
|
||||
(int)$datos['enfermera_id'],
|
||||
$admin,
|
||||
$datos['notas'] ?? ''
|
||||
);
|
||||
|
||||
jsonOk(['id' => $id], 'Enfermera asignada correctamente');
|
||||
} catch (Exception $e) {
|
||||
jsonError($e->getMessage(), 500);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* POST /api/lab/save_config.php — Guardar configuración global del lab
|
||||
* Solo admin.
|
||||
* Body JSON: { empresa_nombre, empresa_subtitulo, empresa_direccion, empresa_telefono,
|
||||
* empresa_email, empresa_ciudad, doc_color, doc_logo_base64, doc_pie_pagina }
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('POST');
|
||||
requireAdmin();
|
||||
|
||||
$datos = inputJson();
|
||||
$db = Database::getInstance();
|
||||
|
||||
$permitidas = [
|
||||
'empresa_nombre', 'empresa_subtitulo', 'empresa_direccion',
|
||||
'empresa_telefono', 'empresa_email', 'empresa_ciudad',
|
||||
'doc_color', 'doc_logo_base64', 'doc_pie_pagina',
|
||||
];
|
||||
|
||||
$guardadas = 0;
|
||||
foreach ($permitidas as $clave) {
|
||||
if (array_key_exists($clave, $datos)) {
|
||||
$db->query(
|
||||
'INSERT INTO lab_config(clave, valor) VALUES(?,?) ON DUPLICATE KEY UPDATE valor=?',
|
||||
[$clave, $datos[$clave], $datos[$clave]]
|
||||
);
|
||||
$guardadas++;
|
||||
}
|
||||
}
|
||||
|
||||
jsonOk(['guardadas' => $guardadas], 'Configuración guardada');
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/**
|
||||
* POST /api/lab/save_domicilio.php
|
||||
* Crea, actualiza o cambia estado de un domicilio.
|
||||
* Body JSON:
|
||||
* { id?, paciente_id, orden_id?, direccion, ciudad?, barrio?,
|
||||
* indicaciones_dir?, fecha_programada, hora_programada?,
|
||||
* tipo_servicio?, estado?,
|
||||
* -- Para cambio de estado solamente:
|
||||
* solo_estado?: true, nuevo_estado?, motivo_cancelacion?, ... }
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('POST');
|
||||
|
||||
try {
|
||||
$datos = inputJson();
|
||||
$dom = new Domicilio();
|
||||
$admin = adminId();
|
||||
|
||||
// Solo cambio de estado
|
||||
if (!empty($datos['id']) && !empty($datos['solo_estado'])) {
|
||||
$id = (int)$datos['id'];
|
||||
$nuevoEstado = $datos['nuevo_estado'] ?? '';
|
||||
$extras = array_filter([
|
||||
'motivo_cancelacion' => $datos['motivo_cancelacion'] ?? null,
|
||||
'fecha_reprogramada' => $datos['fecha_reprogramada'] ?? null,
|
||||
'hora_llegada' => $datos['hora_llegada'] ?? null,
|
||||
'hora_salida' => $datos['hora_salida'] ?? null,
|
||||
'observaciones' => $datos['observaciones'] ?? null,
|
||||
'muestras_tomadas' => $datos['muestras_tomadas'] ?? null,
|
||||
]);
|
||||
$dom->cambiarEstado($id, $nuevoEstado, $admin, $extras);
|
||||
jsonOk(['id' => $id], 'Estado actualizado');
|
||||
}
|
||||
|
||||
if (!empty($datos['id'])) {
|
||||
// Actualización general
|
||||
$id = (int)$datos['id'];
|
||||
unset($datos['id'], $datos['solo_estado']);
|
||||
// Normalizar orden_id: vacío o 0 → null
|
||||
if (isset($datos['orden_id']) && ($datos['orden_id'] === '' || (int)$datos['orden_id'] === 0)) {
|
||||
$datos['orden_id'] = null;
|
||||
}
|
||||
$dom->actualizar($id, $datos, $admin);
|
||||
jsonOk(['id' => $id], 'Domicilio actualizado correctamente');
|
||||
} else {
|
||||
// Creación
|
||||
foreach (['paciente_id', 'direccion', 'fecha_programada'] as $req) {
|
||||
if (empty($datos[$req])) {
|
||||
jsonError("El campo $req es obligatorio");
|
||||
}
|
||||
}
|
||||
// Normalizar orden_id: vacío o 0 → null (evita FK constraint)
|
||||
if (isset($datos['orden_id']) && ($datos['orden_id'] === '' || (int)$datos['orden_id'] === 0)) {
|
||||
$datos['orden_id'] = null;
|
||||
}
|
||||
// Si el creador es un enfermero y no vino enfermera_id, auto-asignarlo desde la sesión
|
||||
if (empty($datos['enfermera_id']) && userRole() === 'enfermero') {
|
||||
$eid = enfermeraId();
|
||||
if ($eid) $datos['enfermera_id'] = $eid;
|
||||
}
|
||||
$id = $dom->crear($datos, $admin);
|
||||
|
||||
// Crear asignación automática si se indicó enfermera_id
|
||||
if (!empty($datos['enfermera_id'])) {
|
||||
$asig = new Asignacion();
|
||||
$asig->asignar($id, (int)$datos['enfermera_id'], $admin);
|
||||
}
|
||||
|
||||
jsonOk(['id' => $id], 'Domicilio creado correctamente');
|
||||
}
|
||||
} catch (InvalidArgumentException $e) {
|
||||
jsonError($e->getMessage());
|
||||
} catch (Exception $e) {
|
||||
jsonError($e->getMessage(), 500);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/**
|
||||
* POST /api/lab/save_enfermera.php
|
||||
* Crea o actualiza una enfermera.
|
||||
* Body JSON:
|
||||
* { id?, nombre_completo, numero_documento, tipo_documento?,
|
||||
* telefono, telefono_alt?, email?, zona?, notas?, is_active? }
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('POST');
|
||||
|
||||
try {
|
||||
$datos = inputJson();
|
||||
$enf = new Enfermera();
|
||||
$admin = adminId();
|
||||
|
||||
if (!empty($datos['id'])) {
|
||||
$id = (int)$datos['id'];
|
||||
unset($datos['id']);
|
||||
|
||||
// Desactivar
|
||||
if (isset($datos['is_active']) && $datos['is_active'] == 0) {
|
||||
$enf->desactivar($id, $admin);
|
||||
jsonOk(['id' => $id], 'Enfermera desactivada');
|
||||
}
|
||||
|
||||
$enf->actualizar($id, $datos, $admin);
|
||||
jsonOk(['id' => $id], 'Enfermera actualizada correctamente');
|
||||
} else {
|
||||
foreach (['nombre_completo', 'numero_documento', 'telefono'] as $req) {
|
||||
if (empty($datos[$req])) {
|
||||
jsonError("El campo $req es obligatorio");
|
||||
}
|
||||
}
|
||||
$id = $enf->crear($datos, $admin);
|
||||
jsonOk(['id' => $id], 'Enfermera registrada correctamente');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
jsonError($e->getMessage(), 500);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/**
|
||||
* POST /api/lab/save_formulario.php
|
||||
* Solo admins pueden crear/editar plantillas.
|
||||
*
|
||||
* Body JSON para crear: { nombre, descripcion?, categoria?, esquema, permite_firma?, requiere_firma? }
|
||||
* Body JSON para editar: { id, ...mismos campos... }
|
||||
* Body JSON para borrar: { id, borrar: true }
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('POST');
|
||||
requireAdmin(); // enfermeros NO pueden diseñar formularios
|
||||
|
||||
try {
|
||||
$datos = inputJson();
|
||||
$form = new Formulario();
|
||||
$admin = adminId();
|
||||
|
||||
// Borrar (soft delete)
|
||||
if (!empty($datos['id']) && !empty($datos['borrar'])) {
|
||||
$form->actualizar((int)$datos['id'], ['is_active' => 0], $admin);
|
||||
jsonOk(['id' => (int)$datos['id']], 'Formulario eliminado');
|
||||
}
|
||||
|
||||
// Editar
|
||||
if (!empty($datos['id'])) {
|
||||
$id = (int)$datos['id'];
|
||||
unset($datos['id']);
|
||||
$form->actualizar($id, $datos, $admin);
|
||||
jsonOk(['id' => $id], 'Formulario actualizado');
|
||||
}
|
||||
|
||||
// Crear
|
||||
if (empty($datos['nombre'])) jsonError('El nombre es obligatorio');
|
||||
if (empty($datos['esquema'])) jsonError('El esquema es obligatorio');
|
||||
|
||||
$id = $form->crear($datos, $admin);
|
||||
jsonOk(['id' => $id], 'Formulario creado correctamente');
|
||||
|
||||
} catch (InvalidArgumentException $e) {
|
||||
jsonError($e->getMessage());
|
||||
} catch (Exception $e) {
|
||||
jsonError($e->getMessage(), 500);
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
/**
|
||||
* POST /api/lab/save_lab_user.php
|
||||
* Crea o actualiza un usuario del sistema.
|
||||
* Solo admins.
|
||||
*
|
||||
* Body JSON:
|
||||
* { id?, username, full_name, email?, password?, role_id, is_active?, enfermera_id? }
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('POST');
|
||||
requireAdmin();
|
||||
|
||||
$body = inputJson();
|
||||
$id = isset($body['id']) ? (int)$body['id'] : null;
|
||||
$username = trim($body['username'] ?? '');
|
||||
$fullName = trim($body['full_name'] ?? '');
|
||||
$email = trim($body['email'] ?? '');
|
||||
$password = $body['password'] ?? '';
|
||||
$roleId = isset($body['role_id']) ? (int)$body['role_id'] : null;
|
||||
$isActive = isset($body['is_active']) ? (int)(bool)$body['is_active'] : 1;
|
||||
$enfermeraId = isset($body['enfermera_id']) && $body['enfermera_id'] !== '' && $body['enfermera_id'] !== null
|
||||
? (int)$body['enfermera_id'] : null;
|
||||
|
||||
if (!$username) jsonError('El nombre de usuario es obligatorio');
|
||||
if (!$fullName) jsonError('El nombre completo es obligatorio');
|
||||
if (!$roleId) jsonError('Debes seleccionar un rol');
|
||||
|
||||
// Validar username (solo alfanumérico + guión bajo)
|
||||
if (!preg_match('/^[a-zA-Z0-9_\.]{3,50}$/', $username)) {
|
||||
jsonError('El username solo puede tener letras, números, puntos y guiones bajos (3-50 caracteres)');
|
||||
}
|
||||
|
||||
$db = Database::getInstance();
|
||||
|
||||
// Obtener slug del rol
|
||||
$role = $db->fetch("SELECT id, slug FROM roles WHERE id = ?", [$roleId]);
|
||||
if (!$role) jsonError('Rol no encontrado', 404);
|
||||
$roleSlug = $role['slug'];
|
||||
|
||||
// Si el rol es enfermero y no hay enfermera_id, buscar si tiene ya uno vinculado
|
||||
// (se puede crear sin vincular y vincularlo después desde la pantalla de Enfermeras)
|
||||
|
||||
if ($id) {
|
||||
// ── Actualizar ──────────────────────────────────────────
|
||||
$existing = $db->fetch("SELECT id, username FROM admin_users WHERE id = ?", [$id]);
|
||||
if (!$existing) jsonError('Usuario no encontrado', 404);
|
||||
|
||||
// Verificar duplicado de username (excluir el propio)
|
||||
$dup = $db->fetch("SELECT id FROM admin_users WHERE username = ? AND id != ?", [$username, $id]);
|
||||
if ($dup) jsonError('Ese nombre de usuario ya está en uso');
|
||||
|
||||
$params = [$username, $fullName, $email ?: null, $roleId, $roleSlug, $isActive, $enfermeraId, $id];
|
||||
$sql = "UPDATE admin_users
|
||||
SET username=?, full_name=?, email=?, role_id=?, role=?, is_active=?, enfermera_id=?, updated_at=NOW()
|
||||
WHERE id=?";
|
||||
|
||||
if ($password) {
|
||||
if (strlen($password) < 6) jsonError('La contraseña debe tener al menos 6 caracteres');
|
||||
$hash = password_hash($password, PASSWORD_BCRYPT);
|
||||
$sql = "UPDATE admin_users
|
||||
SET username=?, full_name=?, email=?, role_id=?, role=?, is_active=?, enfermera_id=?, password_hash=?, updated_at=NOW()
|
||||
WHERE id=?";
|
||||
$params = [$username, $fullName, $email ?: null, $roleId, $roleSlug, $isActive, $enfermeraId, $hash, $id];
|
||||
}
|
||||
|
||||
$db->query($sql, $params);
|
||||
jsonOk(['id' => $id], 'Usuario actualizado correctamente');
|
||||
|
||||
} else {
|
||||
// ── Crear ────────────────────────────────────────────────
|
||||
if (!$password) jsonError('La contraseña es obligatoria al crear un usuario');
|
||||
if (strlen($password) < 6) jsonError('La contraseña debe tener al menos 6 caracteres');
|
||||
|
||||
$dup = $db->fetch("SELECT id FROM admin_users WHERE username = ?", [$username]);
|
||||
if ($dup) jsonError('Ese nombre de usuario ya está en uso');
|
||||
|
||||
$hash = password_hash($password, PASSWORD_BCRYPT);
|
||||
|
||||
$db->query(
|
||||
"INSERT INTO admin_users (username, full_name, email, password_hash, role_id, role, is_active, enfermera_id)
|
||||
VALUES (?,?,?,?,?,?,?,?)",
|
||||
[$username, $fullName, $email ?: null, $hash, $roleId, $roleSlug, $isActive, $enfermeraId]
|
||||
);
|
||||
$newId = $db->lastInsertId();
|
||||
jsonOk(['id' => $newId], 'Usuario creado correctamente');
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* POST /api/lab/save_orden.php
|
||||
* Crea o actualiza datos de una orden médica (sin cambiar estado).
|
||||
* Body JSON:
|
||||
* { id?, paciente_id, conversation_id?, whatsapp_media_id?, local_file?,
|
||||
* medico_nombre?, medico_registro?, fecha_orden?, diagnostico?,
|
||||
* examenes_solicitados?, requiere_ayuno?, horas_ayuno?,
|
||||
* indicaciones?, notas_admin? }
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('POST');
|
||||
|
||||
try {
|
||||
$datos = inputJson();
|
||||
$om = new OrdenMedica();
|
||||
$admin = adminId();
|
||||
|
||||
if (!empty($datos['id'])) {
|
||||
$id = (int)$datos['id'];
|
||||
unset($datos['id']);
|
||||
$om->actualizar($id, $datos, $admin);
|
||||
jsonOk(['id' => $id], 'Orden actualizada correctamente');
|
||||
} else {
|
||||
if (empty($datos['paciente_id'])) {
|
||||
jsonError('El campo paciente_id es obligatorio');
|
||||
}
|
||||
$id = $om->crear($datos, $admin);
|
||||
jsonOk(['id' => $id], 'Orden creada correctamente');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
jsonError($e->getMessage(), 500);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* POST /api/lab/save_paciente.php
|
||||
* Crea o actualiza un paciente.
|
||||
* Body JSON:
|
||||
* { id?, nombre_completo, numero_documento?, tipo_documento?, telefono?,
|
||||
* email?, fecha_nacimiento?, genero?, direccion?, ciudad?, barrio?,
|
||||
* eps?, notas_admin?, user_id? }
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('POST');
|
||||
|
||||
try {
|
||||
$datos = inputJson();
|
||||
$pac = new Paciente();
|
||||
$admin = adminId();
|
||||
|
||||
if (!empty($datos['id'])) {
|
||||
// Actualización
|
||||
$id = (int)$datos['id'];
|
||||
unset($datos['id']);
|
||||
$pac->actualizar($id, $datos, $admin);
|
||||
jsonOk(['id' => $id], 'Paciente actualizado correctamente');
|
||||
} else {
|
||||
// Creación — nombre obligatorio
|
||||
if (empty($datos['nombre_completo'])) {
|
||||
jsonError('El campo nombre_completo es obligatorio');
|
||||
}
|
||||
$id = $pac->crear($datos, $admin);
|
||||
jsonOk(['id' => $id], 'Paciente creado correctamente');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
jsonError($e->getMessage(), 500);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/**
|
||||
* POST /api/lab/save_role.php
|
||||
* Crea o actualiza un rol y sus módulos.
|
||||
* Solo admins.
|
||||
*
|
||||
* Body JSON:
|
||||
* { id?, name, slug, description?, color?, modules: [slug, ...] }
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('POST');
|
||||
requireAdmin();
|
||||
|
||||
$body = inputJson();
|
||||
|
||||
$id = isset($body['id']) ? (int)$body['id'] : null;
|
||||
$name = trim($body['name'] ?? '');
|
||||
$slug = trim($body['slug'] ?? '');
|
||||
$description = trim($body['description'] ?? '');
|
||||
$color = trim($body['color'] ?? '#6c757d');
|
||||
$modules = $body['modules'] ?? [];
|
||||
|
||||
if (!$name) jsonError('El nombre del rol es obligatorio');
|
||||
if (!$slug) jsonError('El slug del rol es obligatorio');
|
||||
if (!preg_match('/^[a-z0-9_\-]+$/', $slug)) jsonError('El slug solo puede contener letras minúsculas, números, guiones y guiones bajos');
|
||||
if (!is_array($modules)) jsonError('modules debe ser un arreglo');
|
||||
|
||||
$db = Database::getInstance();
|
||||
|
||||
// Verificar duplicado de slug
|
||||
$existing = $db->fetch("SELECT id, is_system FROM roles WHERE slug = ?", [$slug]);
|
||||
if ($existing && (!$id || $existing['id'] !== $id)) {
|
||||
jsonError('Ya existe un rol con ese slug');
|
||||
}
|
||||
|
||||
if ($id) {
|
||||
// Actualizar
|
||||
$role = $db->fetch("SELECT id, is_system FROM roles WHERE id = ?", [$id]);
|
||||
if (!$role) jsonError('Rol no encontrado', 404);
|
||||
|
||||
$db->query(
|
||||
"UPDATE roles SET name=?, slug=?, description=?, color=?, updated_at=NOW() WHERE id=?",
|
||||
[$name, $slug, $description, $color, $id]
|
||||
);
|
||||
// Reconstruir módulos solo si no es sistema, o siempre (admin puede editar módulos)
|
||||
$db->query("DELETE FROM role_modules WHERE role_id = ?", [$id]);
|
||||
} else {
|
||||
// Crear
|
||||
$db->query(
|
||||
"INSERT INTO roles (name, slug, description, color) VALUES (?,?,?,?)",
|
||||
[$name, $slug, $description, $color]
|
||||
);
|
||||
$id = $db->lastInsertId();
|
||||
}
|
||||
|
||||
// Insertar módulos
|
||||
foreach ($modules as $mod) {
|
||||
$mod = trim((string)$mod);
|
||||
if ($mod) {
|
||||
$db->query(
|
||||
"INSERT IGNORE INTO role_modules (role_id, module_slug) VALUES (?,?)",
|
||||
[$id, $mod]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
jsonOk(['id' => $id], $id ? 'Rol actualizado' : 'Rol creado');
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* POST /api/lab/save_servicio_extra.php
|
||||
* El enfermero agrega (o actualiza/elimina) un servicio extra a un domicilio.
|
||||
*
|
||||
* Body JSON:
|
||||
* { domicilio_id, descripcion, tipo, notas?, requiere_pago?, valor? } -- crear
|
||||
* { id, descripcion?, tipo?, notas?, requiere_pago?, valor? } -- editar
|
||||
* { id, eliminar: true } -- borrar
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('POST');
|
||||
|
||||
$TIPOS_VALIDOS = ['inyeccion','cura','nebulizacion','toma_muestra',
|
||||
'tension_arterial','glucometria','otro'];
|
||||
|
||||
try {
|
||||
$datos = inputJson();
|
||||
$db = Database::getInstance();
|
||||
|
||||
// ── Eliminar ───────────────────────────────────────────────────────────
|
||||
if (!empty($datos['id']) && !empty($datos['eliminar'])) {
|
||||
$se = $db->fetch('SELECT * FROM lab_servicios_extra WHERE id = ?', [(int)$datos['id']]);
|
||||
if (!$se) jsonError('Servicio no encontrado', 404);
|
||||
if (userRole() === 'enfermero') {
|
||||
requireEnfermeroAccess((int)$se['realizado_por']);
|
||||
}
|
||||
$db->delete('lab_servicios_extra', 'id = ?', [(int)$datos['id']]);
|
||||
jsonOk(['id' => (int)$datos['id']], 'Servicio eliminado');
|
||||
}
|
||||
|
||||
// ── Editar ─────────────────────────────────────────────────────────────
|
||||
if (!empty($datos['id'])) {
|
||||
$id = (int)$datos['id'];
|
||||
$se = $db->fetch('SELECT * FROM lab_servicios_extra WHERE id = ?', [$id]);
|
||||
if (!$se) jsonError('Servicio no encontrado', 404);
|
||||
if (userRole() === 'enfermero') {
|
||||
requireEnfermeroAccess((int)$se['realizado_por']);
|
||||
}
|
||||
$permitidos = ['descripcion','tipo','notas','requiere_pago','valor'];
|
||||
$campos = array_intersect_key($datos, array_flip($permitidos));
|
||||
if (isset($campos['tipo']) && !in_array($campos['tipo'], $TIPOS_VALIDOS)) {
|
||||
jsonError('Tipo de servicio inválido');
|
||||
}
|
||||
$db->update('lab_servicios_extra', $campos, 'id = ?', [$id]);
|
||||
jsonOk(['id' => $id], 'Servicio actualizado');
|
||||
}
|
||||
|
||||
// ── Crear ──────────────────────────────────────────────────────────────
|
||||
foreach (['domicilio_id', 'descripcion', 'tipo'] as $req) {
|
||||
if (empty($datos[$req])) jsonError("El campo $req es obligatorio");
|
||||
}
|
||||
if (!in_array($datos['tipo'], $TIPOS_VALIDOS)) {
|
||||
jsonError('Tipo de servicio inválido');
|
||||
}
|
||||
|
||||
// Verificar que el domicilio existe y que el enfermero le pertenece
|
||||
$domId = (int)$datos['domicilio_id'];
|
||||
if (userRole() === 'enfermero') {
|
||||
$eid = enfermeraId();
|
||||
$asig = $db->fetch(
|
||||
'SELECT a.id FROM lab_asignaciones a WHERE a.domicilio_id = ? AND a.enfermera_id = ?',
|
||||
[$domId, $eid]
|
||||
);
|
||||
if (!$asig) jsonError('No tienes permiso para este domicilio', 403);
|
||||
}
|
||||
|
||||
$id = $db->insert('lab_servicios_extra', [
|
||||
'domicilio_id' => $domId,
|
||||
'descripcion' => trim($datos['descripcion']),
|
||||
'tipo' => $datos['tipo'],
|
||||
'notas' => $datos['notas'] ?? null,
|
||||
'requiere_pago' => !empty($datos['requiere_pago']) ? 1 : 0,
|
||||
'valor' => !empty($datos['valor']) ? (float)$datos['valor'] : null,
|
||||
'realizado_por' => enfermeraId() ?? (userRole() === 'admin' ? null : null),
|
||||
]);
|
||||
|
||||
jsonOk(['id' => $id], 'Servicio extra registrado');
|
||||
|
||||
} catch (Exception $e) {
|
||||
jsonError($e->getMessage(), 500);
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
/**
|
||||
* POST /api/lab/send_formulario.php
|
||||
* Crea un envío (instancia) con datos pre-llenados y devuelve el link para WhatsApp.
|
||||
* Accesible por admin Y enfermero.
|
||||
*
|
||||
* Body JSON:
|
||||
* { formulario_id, paciente_id?, domicilio_id?, datos_prefilled:{...}, enviado_via? }
|
||||
*
|
||||
* Returns:
|
||||
* { id, token, url, whatsapp_url, mensaje_wa }
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('POST');
|
||||
|
||||
try {
|
||||
$datos = inputJson();
|
||||
|
||||
if (empty($datos['formulario_id'])) jsonError('formulario_id es obligatorio');
|
||||
|
||||
// Verificar que la plantilla existe
|
||||
$form = new Formulario();
|
||||
$plantilla = $form->obtener((int)$datos['formulario_id']);
|
||||
if (!$plantilla) jsonError('Formulario no encontrado', 404);
|
||||
|
||||
// Pre-llenado: si viene paciente_id, auto-enriquecer con datos del paciente
|
||||
$prefilled = $datos['datos_prefilled'] ?? [];
|
||||
if (!empty($datos['paciente_id'])) {
|
||||
$pac = (new Paciente())->obtener((int)$datos['paciente_id']);
|
||||
if ($pac) {
|
||||
// Mapeo automático de campos estándar
|
||||
$prefilled['__paciente'] = [
|
||||
'id' => $pac['id'],
|
||||
'nombre_completo' => $pac['nombre_completo'],
|
||||
'numero_documento'=> $pac['numero_documento'],
|
||||
'tipo_documento' => $pac['tipo_documento'],
|
||||
'telefono' => $pac['telefono'],
|
||||
'email' => $pac['email'] ?? '',
|
||||
'fecha_nacimiento'=> $pac['fecha_nacimiento'] ?? '',
|
||||
'eps' => $pac['eps'] ?? '',
|
||||
'direccion' => $pac['direccion'] ?? '',
|
||||
'ciudad' => $pac['ciudad'] ?? '',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$datos['datos_prefilled'] = json_encode($prefilled, JSON_UNESCAPED_UNICODE);
|
||||
$datos['enviado_via'] = $datos['enviado_via'] ?? 'whatsapp';
|
||||
|
||||
$envioId = $form->crearEnvio($datos, adminId());
|
||||
|
||||
// Construir URL pública
|
||||
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
|
||||
$host = $_SERVER['HTTP_HOST'] ?? 'localhost';
|
||||
$base = $protocol . '://' . $host;
|
||||
// Subir un nivel desde /api/lab/
|
||||
$basePath = rtrim(dirname(dirname(dirname($_SERVER['SCRIPT_NAME']))), '/');
|
||||
|
||||
// Obtener el token del envío recién creado
|
||||
$db = Database::getInstance();
|
||||
$envio = $db->fetch('SELECT token FROM lab_form_envios WHERE id = ?', [$envioId]);
|
||||
$token = $envio['token'];
|
||||
$url = $base . $basePath . '/form_cliente.php?t=' . $token;
|
||||
|
||||
// Mensaje de WhatsApp preformateado
|
||||
$nomPac = $prefilled['__paciente']['nombre_completo'] ?? 'Estimado paciente';
|
||||
$nomForm = $plantilla['nombre'];
|
||||
$mensajeWa = "Hola $nomPac, le enviamos el formulario *\"$nomForm\"* para que lo complete y firme digitalmente.\n\n"
|
||||
. "👉 Accede aquí:\n$url\n\n"
|
||||
. "El enlace expira en 7 días. Si tiene dudas contáctenos.";
|
||||
|
||||
$telPac = $prefilled['__paciente']['telefono'] ?? '';
|
||||
$waUrl = 'https://wa.me/' . preg_replace('/\D/', '', $telPac)
|
||||
. '?text=' . rawurlencode($mensajeWa);
|
||||
|
||||
jsonOk([
|
||||
'id' => $envioId,
|
||||
'token' => $token,
|
||||
'url' => $url,
|
||||
'whatsapp_url'=> $waUrl,
|
||||
'mensaje_wa' => $mensajeWa,
|
||||
], 'Envío creado correctamente');
|
||||
|
||||
} catch (Exception $e) {
|
||||
jsonError($e->getMessage(), 500);
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
/**
|
||||
* POST /api/lab/submit_formulario.php — Guardar respuesta del cliente (público, sin auth)
|
||||
* GET /api/lab/submit_formulario.php?t=TOKEN — Verificar estado del token (público)
|
||||
*
|
||||
* Body JSON (POST): { token, datos_cliente:{...}, firma_svg? }
|
||||
*/
|
||||
// No usar _helpers.php porque este endpoint es PÚBLICO (no requiere sesión)
|
||||
require_once __DIR__ . '/../../config/config.php';
|
||||
require_once __DIR__ . '/../../classes/lab/Formulario.php';
|
||||
require_once __DIR__ . '/../../classes/Database.php';
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
|
||||
header('Access-Control-Allow-Headers: Content-Type');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(204); exit; }
|
||||
|
||||
function pubOk(array $data = [], string $msg = ''): void {
|
||||
$r = ['success' => true];
|
||||
if ($msg) $r['message'] = $msg;
|
||||
echo json_encode(array_merge($r, $data), JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
function pubErr(string $msg, int $code = 400): void {
|
||||
http_response_code($code);
|
||||
echo json_encode(['success' => false, 'error' => $msg], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$form = new Formulario();
|
||||
|
||||
// GET: cargar datos del formulario por token
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
$token = $_GET['t'] ?? '';
|
||||
if (!$token) pubErr('Token requerido');
|
||||
$envio = $form->obtenerPorToken($token);
|
||||
if (!$envio) pubErr('Link inválido o expirado', 404);
|
||||
|
||||
// Config de diseño: primero override del formulario, luego config global
|
||||
$db2 = Database::getInstance();
|
||||
$cfgRows = $db2->fetchAll('SELECT clave, valor FROM lab_config ORDER BY clave');
|
||||
$gCfg = [];
|
||||
foreach ($cfgRows as $r) { $gCfg[$r['clave']] = $r['valor']; }
|
||||
$docConfig = [
|
||||
'doc_color' => $envio['doc_color'] ?: ($gCfg['doc_color'] ?? '#1565c0'),
|
||||
'doc_logo_base64' => $envio['doc_logo_base64'] ?: ($gCfg['doc_logo_base64'] ?? null),
|
||||
'doc_encabezado' => $envio['doc_encabezado'] ?: ($gCfg['empresa_nombre'] ?? null),
|
||||
'doc_subtitulo' => $envio['doc_subtitulo'] ?: ($gCfg['empresa_subtitulo'] ?? null),
|
||||
'doc_pie_pagina' => $envio['doc_pie_pagina'] ?: ($gCfg['doc_pie_pagina'] ?? null),
|
||||
];
|
||||
|
||||
// Estructura que espera form_cliente.php
|
||||
pubOk([
|
||||
'formulario' => [
|
||||
'nombre' => $envio['form_nombre'],
|
||||
'descripcion' => $envio['form_descripcion'] ?? '',
|
||||
'esquema_decoded'=> $envio['esquema_decoded'],
|
||||
'permite_firma' => (bool)($envio['permite_firma'] ?? false),
|
||||
'requiere_firma' => (bool)($envio['requiere_firma'] ?? false),
|
||||
],
|
||||
'envio' => [
|
||||
'id' => $envio['id'],
|
||||
'estado' => $envio['estado'],
|
||||
'firma_svg' => $envio['firma_svg'] ?? null,
|
||||
'hash_verificacion'=> $envio['hash_verificacion'] ?? null,
|
||||
'completado_en' => $envio['completado_en'] ?? null,
|
||||
],
|
||||
'prefilled' => $envio['prefilled_decoded'] ?? [],
|
||||
'config' => $docConfig,
|
||||
]);
|
||||
}
|
||||
|
||||
// POST: guardar respuesta
|
||||
$raw = file_get_contents('php://input');
|
||||
$datos = json_decode($raw, true) ?? [];
|
||||
|
||||
$token = $datos['token'] ?? '';
|
||||
if (!$token) pubErr('Token requerido');
|
||||
|
||||
$envio = $form->obtenerPorToken($token);
|
||||
if (!$envio) pubErr('Link inválido o expirado', 404);
|
||||
|
||||
if (in_array($envio['estado'], ['completado', 'firmado'])) {
|
||||
// El formulario ya fue guardado (posible reintento tras error de red).
|
||||
// Devolvemos éxito con los datos existentes para que el cliente no quede bloqueado.
|
||||
$db = Database::getInstance();
|
||||
$saved = $db->fetch('SELECT id, hash_verificacion, firma_svg FROM lab_form_envios WHERE token = ?', [$token]);
|
||||
pubOk([
|
||||
'firmado' => !empty($saved['firma_svg']),
|
||||
'hash' => $saved['hash_verificacion'] ?? null,
|
||||
'envio_id' => $saved['id'] ?? null,
|
||||
'ya_enviado'=> true,
|
||||
], 'Formulario enviado correctamente. ¡Gracias!');
|
||||
}
|
||||
|
||||
$datosCliente = $datos['datos_cliente'] ?? [];
|
||||
$firmaSvg = $datos['firma_svg'] ?? null;
|
||||
$firmaFoto = $datos['firma_foto'] ?? null;
|
||||
|
||||
// Guardar foto de firma dentro de datos_cliente para no requerir nueva columna
|
||||
if ($firmaFoto) {
|
||||
$datosCliente['__firma_foto'] = $firmaFoto;
|
||||
}
|
||||
|
||||
// Validar que si requiere firma, venga
|
||||
if ($envio['requiere_firma'] && !$firmaSvg) {
|
||||
pubErr('La firma es obligatoria para este formulario');
|
||||
}
|
||||
|
||||
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? '';
|
||||
$ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
|
||||
|
||||
$ok = $form->guardarRespuesta($token, $datosCliente, $firmaSvg, $ip, $ua);
|
||||
if (!$ok) pubErr('No se pudo guardar la respuesta', 500);
|
||||
|
||||
// Recuperar hash e id para la respuesta
|
||||
$db = Database::getInstance();
|
||||
$saved = $db->fetch('SELECT id, hash_verificacion FROM lab_form_envios WHERE token = ?', [$token]);
|
||||
|
||||
pubOk([
|
||||
'firmado' => (bool)$firmaSvg,
|
||||
'hash' => $saved['hash_verificacion'] ?? null,
|
||||
'envio_id' => $saved['id'] ?? null,
|
||||
], 'Formulario enviado correctamente. ¡Gracias!');
|
||||
|
||||
} catch (Exception $e) {
|
||||
pubErr($e->getMessage(), 500);
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
* POST /api/lab/update_domicilio_enfermero.php
|
||||
* El enfermero actualiza el estado de un domicilio asignado.
|
||||
*
|
||||
* Body JSON:
|
||||
* { domicilio_id, nuevo_estado, notas? }
|
||||
*
|
||||
* Transiciones permitidas al enfermero:
|
||||
* programado → confirmado
|
||||
* confirmado → en_camino
|
||||
* en_camino → en_domicilio
|
||||
* en_domicilio → completado
|
||||
* cualquiera → cancelado (con notas obligatorias)
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('POST');
|
||||
|
||||
// Flujo permitido enfermero: estado_actual => [estados_siguientes_posibles]
|
||||
const TRANSICIONES_ENFERMERO = [
|
||||
'programado' => ['confirmado'],
|
||||
'confirmado' => ['en_camino', 'cancelado'],
|
||||
'en_camino' => ['en_domicilio', 'cancelado'],
|
||||
'en_domicilio' => ['completado', 'cancelado'],
|
||||
];
|
||||
|
||||
try {
|
||||
$datos = inputJson();
|
||||
$domId = (int)($datos['domicilio_id'] ?? 0);
|
||||
$estado = trim($datos['nuevo_estado'] ?? '');
|
||||
$notas = trim($datos['notas'] ?? '');
|
||||
|
||||
if (!$domId) jsonError('domicilio_id requerido');
|
||||
if (!$estado) jsonError('nuevo_estado requerido');
|
||||
|
||||
$db = Database::getInstance();
|
||||
|
||||
// Verificar domicilio y obtener estado actual
|
||||
$dom = $db->fetch(
|
||||
'SELECT id, estado, paciente_id FROM lab_domicilios WHERE id = ?',
|
||||
[$domId]
|
||||
);
|
||||
if (!$dom) jsonError('Domicilio no encontrado', 404);
|
||||
|
||||
// Verificar que el enfermero tenga asignación activa
|
||||
if (userRole() === 'enfermero') {
|
||||
$eid = enfermeraId();
|
||||
$asig = $db->fetch(
|
||||
"SELECT a.id FROM lab_asignaciones a
|
||||
WHERE a.domicilio_id = ? AND a.enfermera_id = ?
|
||||
AND a.estado NOT IN ('liberada','completada')",
|
||||
[$domId, $eid]
|
||||
);
|
||||
if (!$asig) jsonError('No tienes asignación activa para este domicilio', 403);
|
||||
|
||||
// Validar transición
|
||||
$estadoActual = $dom['estado'];
|
||||
$permitidos = TRANSICIONES_ENFERMERO[$estadoActual] ?? [];
|
||||
if (!in_array($estado, $permitidos)) {
|
||||
jsonError("No puedes pasar de '$estadoActual' a '$estado'");
|
||||
}
|
||||
}
|
||||
|
||||
if ($estado === 'cancelado' && !$notas) {
|
||||
jsonError('Las notas son obligatorias al cancelar');
|
||||
}
|
||||
|
||||
// Actualizar domicilio
|
||||
$campos = ['estado' => $estado];
|
||||
if ($notas) $campos['notas_admin'] = $notas;
|
||||
if ($estado === 'completado') {
|
||||
$campos['hora_salida'] = date('H:i:s');
|
||||
}
|
||||
if ($estado === 'en_domicilio') {
|
||||
$campos['hora_llegada'] = date('H:i:s');
|
||||
}
|
||||
$db->update('lab_domicilios', $campos, 'id = ?', [$domId]);
|
||||
|
||||
// Actualizar asignación si completado/cancelado
|
||||
if (in_array($estado, ['completado', 'cancelado']) && userRole() === 'enfermero') {
|
||||
$estAsig = $estado === 'completado' ? 'completada' : 'liberada';
|
||||
$db->update(
|
||||
'lab_asignaciones',
|
||||
['estado' => $estAsig],
|
||||
'domicilio_id = ? AND enfermera_id = ?',
|
||||
[$domId, enfermeraId()]
|
||||
);
|
||||
}
|
||||
|
||||
jsonOk(['domicilio_id' => $domId, 'estado' => $estado], 'Estado actualizado correctamente');
|
||||
|
||||
} catch (Exception $e) {
|
||||
jsonError($e->getMessage(), 500);
|
||||
}
|
||||
+16
-11
@@ -15,18 +15,23 @@ header('Cache-Control: no-cache, no-store, must-revalidate');
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
|
||||
// Obtener todos los usuarios administradores
|
||||
// Obtener todos los usuarios administradores con info de rol
|
||||
$users = $db->fetchAll("
|
||||
SELECT
|
||||
id,
|
||||
username,
|
||||
full_name,
|
||||
email,
|
||||
is_active,
|
||||
last_login,
|
||||
created_at
|
||||
FROM admin_users
|
||||
ORDER BY created_at DESC
|
||||
SELECT
|
||||
u.id,
|
||||
u.username,
|
||||
u.full_name,
|
||||
u.email,
|
||||
u.is_active,
|
||||
u.role,
|
||||
u.role_id,
|
||||
u.last_login,
|
||||
u.created_at,
|
||||
r.name AS role_name,
|
||||
r.color AS role_color
|
||||
FROM admin_users u
|
||||
LEFT JOIN roles r ON r.id = u.role_id
|
||||
ORDER BY u.created_at DESC
|
||||
");
|
||||
|
||||
echo json_encode([
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
/**
|
||||
* API - Subir documento PDF de Términos y Condiciones
|
||||
*/
|
||||
|
||||
require_once '../config/config.php';
|
||||
|
||||
error_reporting(E_ALL);
|
||||
@ini_set('display_errors', 0);
|
||||
@ini_set('log_errors', 1);
|
||||
|
||||
requireAuthentication();
|
||||
|
||||
if (ob_get_level() === 0) ob_start();
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Methods: POST');
|
||||
header('Access-Control-Allow-Headers: Content-Type');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
echo json_encode(['success' => false, 'error' => 'Método no permitido']);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
|
||||
// ── Guardar/actualizar configuración de texto ──────────────────────────
|
||||
// Si se envía sin archivo (solo textos), actualizar la versión activa.
|
||||
$msgAceptacion = trim($_POST['mensaje_aceptacion'] ?? '');
|
||||
$msgRechazo = trim($_POST['mensaje_rechazo'] ?? '');
|
||||
$version = trim($_POST['version'] ?? '');
|
||||
$forzarReenvio = !empty($_POST['forzar_reenvio']) ? 1 : 0;
|
||||
|
||||
// ── Determinar si hay un archivo ───────────────────────────────────────
|
||||
$hasFile = isset($_FILES['pdf']) && $_FILES['pdf']['error'] === UPLOAD_ERR_OK;
|
||||
|
||||
if ($hasFile) {
|
||||
$file = $_FILES['pdf'];
|
||||
$tmpPath = $file['tmp_name'];
|
||||
$mime = mime_content_type($tmpPath);
|
||||
|
||||
// Validar que sea PDF
|
||||
if ($mime !== 'application/pdf') {
|
||||
if (ob_get_length()) ob_clean();
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'error' => 'Solo se permite subir archivos PDF']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Tamaño máximo 20 MB
|
||||
if ($file['size'] > 20 * 1024 * 1024) {
|
||||
if (ob_get_length()) ob_clean();
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'error' => 'El archivo no puede superar 20 MB']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Crear directorio de destino si no existe
|
||||
$uploadDir = __DIR__ . '/../uploads/terms/';
|
||||
if (!is_dir($uploadDir)) {
|
||||
mkdir($uploadDir, 0755, true);
|
||||
}
|
||||
|
||||
// Nombre único para evitar sobreescribir
|
||||
$safeName = 'terminos_' . date('Ymd_His') . '_' . bin2hex(random_bytes(4)) . '.pdf';
|
||||
$destPath = $uploadDir . $safeName;
|
||||
|
||||
if (!move_uploaded_file($tmpPath, $destPath)) {
|
||||
throw new Exception('Error al guardar el archivo en el servidor');
|
||||
}
|
||||
|
||||
// URL pública
|
||||
$baseUrl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http')
|
||||
. '://' . $_SERVER['HTTP_HOST'];
|
||||
// Calcular ruta relativa desde la raíz del proyecto
|
||||
$docRoot = rtrim($_SERVER['DOCUMENT_ROOT'], '/');
|
||||
$absUpload = realpath($destPath);
|
||||
$relPath = '/' . ltrim(str_replace($docRoot, '', $absUpload), '/');
|
||||
$docUrl = $baseUrl . $relPath;
|
||||
}
|
||||
|
||||
// ── Desactivar versiones anteriores si se crea una nueva ──────────────
|
||||
if ($hasFile || !empty($version)) {
|
||||
// Si hay archivo o versión nueva, desactivar la anterior y crear registro nuevo
|
||||
$db->query("UPDATE terms_versions SET activa = 0 WHERE activa = 1");
|
||||
|
||||
$insertData = [
|
||||
'version' => $version ?: date('Y-m'),
|
||||
'mensaje_aceptacion' => $msgAceptacion,
|
||||
'mensaje_rechazo' => $msgRechazo,
|
||||
'forzar_reenvio' => $forzarReenvio,
|
||||
'activa' => 1,
|
||||
];
|
||||
|
||||
if ($hasFile) {
|
||||
$insertData['documento_url'] = $docUrl ?? null;
|
||||
$insertData['documento_nombre'] = $file['name'];
|
||||
}
|
||||
|
||||
$newId = $db->insert('terms_versions', $insertData);
|
||||
|
||||
// Si forzar_reenvio=1, resetear terms_pending en todos los usuarios para forzar re-lectura
|
||||
if ($forzarReenvio) {
|
||||
$db->query(
|
||||
"UPDATE users SET terms_pending = 0, terms_accepted_at = NULL, terms_version_id = NULL"
|
||||
);
|
||||
}
|
||||
|
||||
if (ob_get_length()) ob_clean();
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'version_id' => $newId,
|
||||
'documento_url' => $insertData['documento_url'] ?? null,
|
||||
'message' => 'Términos guardados correctamente',
|
||||
]);
|
||||
} else {
|
||||
// Sin archivo ni versión → solo actualizar textos de la versión activa
|
||||
$active = $db->fetch("SELECT id FROM terms_versions WHERE activa = 1 ORDER BY id DESC LIMIT 1");
|
||||
if ($active) {
|
||||
$updateData = [];
|
||||
if ($msgAceptacion !== '') $updateData['mensaje_aceptacion'] = $msgAceptacion;
|
||||
if ($msgRechazo !== '') $updateData['mensaje_rechazo'] = $msgRechazo;
|
||||
$updateData['forzar_reenvio'] = $forzarReenvio;
|
||||
$db->update('terms_versions', $updateData, 'id = :id', ['id' => $active['id']]);
|
||||
|
||||
if ($forzarReenvio) {
|
||||
$db->query("UPDATE users SET terms_pending = 0, terms_accepted_at = NULL, terms_version_id = NULL");
|
||||
}
|
||||
|
||||
if (ob_get_length()) ob_clean();
|
||||
echo json_encode(['success' => true, 'message' => 'Configuración de términos actualizada']);
|
||||
} else {
|
||||
if (ob_get_length()) ob_clean();
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'error' => 'No hay versión activa. Sube un documento primero.']);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log('upload_terms_document.php error: ' . $e->getMessage());
|
||||
if (ob_get_length()) ob_clean();
|
||||
http_response_code(500);
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
}
|
||||
@@ -560,3 +560,341 @@
|
||||
[2026-02-21 08:43:43] Auto-download failed for media 1217156256734654: Graph API fetch failed:
|
||||
[2026-02-21 08:43:43] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-02-21 08:43:43] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-02-21 09:03:28] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-02-21 09:03:28] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-02-21 09:03:29] Auto-download failed for media 1217156256734654: Graph API fetch failed:
|
||||
[2026-02-21 09:03:29] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-02-21 09:03:29] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"A5iussOysleNqD_H3h6YqZ_"}}
|
||||
[2026-02-21 09:03:29] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-02-21 09:03:29] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-02-21 09:03:29] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-02-21 09:03:29] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"Alzc9zFuoIholZAYNlHTYj1"}}
|
||||
[2026-02-21 09:03:29] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-02-21 09:03:29] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-02-21 11:19:20] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-02-21 11:19:20] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-02-21 11:19:20] Auto-download failed for media 1217156256734654: Graph API fetch failed:
|
||||
[2026-02-21 11:19:20] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-02-21 11:19:20] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AJqoxZ4zAsaS-mNb208AiEo"}}
|
||||
[2026-02-21 11:19:20] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-02-21 11:19:21] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-02-21 11:19:26] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-02-21 11:19:26] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-02-21 11:19:26] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AisVkuFtWeUX2QwmhG1lqMx"}}
|
||||
[2026-02-21 11:19:26] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-02-21 11:19:26] Auto-download failed for media 1217156256734654: Graph API fetch failed:
|
||||
[2026-02-21 11:19:26] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-02-21 11:19:27] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-02-21 11:27:39] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-02-21 11:27:39] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-02-21 11:27:39] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AMnrK4EUy2AxN_FcOyJd0Qy"}}
|
||||
[2026-02-21 11:27:39] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-02-21 11:27:39] Auto-download failed for media 1217156256734654: Graph API fetch failed:
|
||||
[2026-02-21 11:27:39] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-02-21 11:27:40] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-02-21 11:44:53] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-02-21 11:44:53] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-02-21 11:44:53] Auto-download failed for media 1217156256734654: Graph API fetch failed:
|
||||
[2026-02-21 11:44:53] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-02-21 11:44:53] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"ANVda7F7ksRwxiU6oSPaxpP"}}
|
||||
[2026-02-21 11:44:53] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-02-21 11:44:53] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-02-21 11:45:00] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-02-21 11:45:00] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-02-21 11:45:00] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"Az1YG8RtWuRKoygP0Oa9_W-"}}
|
||||
[2026-02-21 11:45:00] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-02-21 11:45:00] Auto-download failed for media 1217156256734654: Graph API fetch failed:
|
||||
[2026-02-21 11:45:00] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-02-21 11:45:00] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-02-21 11:45:12] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-02-21 11:45:12] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-02-21 11:45:13] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AoPzxrE55hgFxTob08WBJhL"}}
|
||||
[2026-02-21 11:45:13] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-02-21 11:45:13] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-02-21 11:45:13] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-02-21 11:45:13] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-02-21 11:45:17] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-02-21 11:45:17] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-02-21 11:45:17] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AbGjiOPlXxbWchiwJ6CyXqW"}}
|
||||
[2026-02-21 11:45:17] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-02-21 11:45:17] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-02-21 11:45:17] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-02-21 11:45:17] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-02 11:30:52] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-02 11:30:52] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-02 11:30:53] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AZGri-6Z0DMgmM1A1sR8Pe7"}}
|
||||
[2026-03-02 11:30:53] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-02 11:30:53] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-02 11:30:53] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-02 11:30:53] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-02 11:30:54] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-02 11:30:54] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AOXECMUo93esakpIwFUpqYB"}}
|
||||
[2026-03-02 11:30:54] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-02 11:30:55] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-02 11:44:04] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-02 11:44:04] Request: GET /api/version/media-url.php?id=1551128883003002 GET:{"id":"1551128883003002"} POST:[]
|
||||
[2026-03-02 11:44:04] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-02 11:44:04] Request: GET /api/version/media-url.php?id=893454973089562 GET:{"id":"893454973089562"} POST:[]
|
||||
[2026-03-02 11:44:04] Serving local file for media ID 1551128883003002: /var/www/html/uploads/media_6979a044c17079.66378227.ogg
|
||||
[2026-03-02 11:44:04] Serving local file for media ID 893454973089562: /var/www/html/uploads/media_6979a3c5b236e8.04274010.ogg
|
||||
[2026-03-02 11:44:05] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AWIFhWSCUfg32iSw3oHxfDI"}}
|
||||
[2026-03-02 11:44:05] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-02 11:44:05] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-02 11:44:05] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-02 11:44:05] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-02 11:44:05] Request: GET /api/version/media-url.php?id=759892943831328 GET:{"id":"759892943831328"} POST:[]
|
||||
[2026-03-02 11:44:05] Request: GET /api/version/media-url.php?id=1334972502008596 GET:{"id":"1334972502008596"} POST:[]
|
||||
[2026-03-02 11:44:05] Request: GET /api/version/media-url.php?id=1601261651067176 GET:{"id":"1601261651067176"} POST:[]
|
||||
[2026-03-02 11:44:06] Request: GET /api/version/media-url.php?id=1043532494648003 GET:{"id":"1043532494648003"} POST:[]
|
||||
[2026-03-02 11:44:06] Serving local file for media ID 759892943831328: /var/www/html/uploads/media_6979a485787858.65742730.ogg
|
||||
[2026-03-02 11:44:06] Serving local file for media ID 1334972502008596: /var/www/html/uploads/media_6979a5b4690f83.69035164.ogg
|
||||
[2026-03-02 11:44:06] Request: GET /api/version/media-url.php?id=2079449202816102 GET:{"id":"2079449202816102"} POST:[]
|
||||
[2026-03-02 11:44:06] Serving local file for media ID 1601261651067176: /var/www/html/uploads/media_6979a9a3d39a72.62917885.ogg
|
||||
[2026-03-02 11:44:06] Serving local file for media ID 2079449202816102: /var/www/html/uploads/media_6979b17f07a0f4.63241756.mp4
|
||||
[2026-03-02 11:44:07] Serving local file for media ID 1043532494648003: /var/www/html/uploads/media_6979abd12b8131.97353205.ogg
|
||||
[2026-03-02 11:44:07] Request: GET /api/version/media-url.php?id=1551128883003002 GET:{"id":"1551128883003002"} POST:[]
|
||||
[2026-03-02 11:44:07] Request: GET /api/version/media-url.php?id=893454973089562 GET:{"id":"893454973089562"} POST:[]
|
||||
[2026-03-02 11:44:07] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-02 11:44:07] Serving local file for media ID 1551128883003002: /var/www/html/uploads/media_6979a044c17079.66378227.ogg
|
||||
[2026-03-02 11:44:07] Serving local file for media ID 893454973089562: /var/www/html/uploads/media_6979a3c5b236e8.04274010.ogg
|
||||
[2026-03-02 11:44:08] Request: GET /api/version/media-url.php?id=1334972502008596 GET:{"id":"1334972502008596"} POST:[]
|
||||
[2026-03-02 11:44:08] Request: GET /api/version/media-url.php?id=759892943831328 GET:{"id":"759892943831328"} POST:[]
|
||||
[2026-03-02 11:44:08] Serving local file for media ID 1334972502008596: /var/www/html/uploads/media_6979a5b4690f83.69035164.ogg
|
||||
[2026-03-02 11:44:08] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AnUP3aPhugLtqpAIj5gV7hY"}}
|
||||
[2026-03-02 11:44:08] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-02 11:44:08] Serving local file for media ID 759892943831328: /var/www/html/uploads/media_6979a485787858.65742730.ogg
|
||||
[2026-03-02 11:44:08] Request: GET /api/version/media-url.php?id=1601261651067176 GET:{"id":"1601261651067176"} POST:[]
|
||||
[2026-03-02 11:44:08] Request: GET /api/version/media-url.php?id=1043532494648003 GET:{"id":"1043532494648003"} POST:[]
|
||||
[2026-03-02 11:44:08] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-02 11:44:09] Serving local file for media ID 1601261651067176: /var/www/html/uploads/media_6979a9a3d39a72.62917885.ogg
|
||||
[2026-03-02 11:44:09] Serving local file for media ID 1043532494648003: /var/www/html/uploads/media_6979abd12b8131.97353205.ogg
|
||||
[2026-03-02 11:44:10] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-02 11:44:10] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"ApY5M23GqHWpJWH8zonLpm4"}}
|
||||
[2026-03-02 11:44:10] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-02 11:44:10] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-03 15:33:11] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-03 15:33:11] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-03 15:33:12] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AcxD9u_TB-joWwYfreaHjC2"}}
|
||||
[2026-03-03 15:33:12] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-03 15:33:12] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-03 15:33:12] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-03 15:33:12] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-03 15:33:49] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-03 15:33:50] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-03 15:33:50] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AbtUJe0Nmk36wiWNfhue_h7"}}
|
||||
[2026-03-03 15:33:50] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-03 15:33:50] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-03 15:33:51] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-03 15:33:51] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-03 15:42:36] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-03 15:42:36] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-03 15:42:37] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"ATZVuoQTYbOHnlvCZpRsd-Y"}}
|
||||
[2026-03-03 15:42:37] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-03 15:42:37] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-03 15:42:37] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-03 15:42:37] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-03 15:42:42] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-03 15:42:42] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-03 15:42:42] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AOKgh1d-JiezKEWC9lJxPf8"}}
|
||||
[2026-03-03 15:42:42] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-03 15:42:43] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-03 15:42:43] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-03 15:42:43] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-03 16:14:55] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-03 16:14:55] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-03 16:14:56] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-03 16:14:56] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-03 16:14:56] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AktmTcgRtxp3ASb0WsQanLk"}}
|
||||
[2026-03-03 16:14:56] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-03 16:14:56] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-03 18:02:12] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-03 18:02:12] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-03 18:02:13] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-03 18:02:13] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-03 18:02:13] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AaqmOWStyN4bNAec5giL9Ym"}}
|
||||
[2026-03-03 18:02:13] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-03 18:02:13] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-03 18:12:46] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-03 18:12:46] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-03 18:12:47] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AS4OBeTbrmdjdjvcVm4XDym"}}
|
||||
[2026-03-03 18:12:47] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-03 18:12:47] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-03 18:12:47] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-03 18:12:47] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-03 18:18:54] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-03 18:18:55] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-03 18:18:56] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AVZ_WGk3WGsMwUTojFSvT3X"}}
|
||||
[2026-03-03 18:18:56] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-03 18:18:56] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-03 18:18:56] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-03 18:18:56] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-03 18:26:33] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-03 18:26:33] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-03 18:26:34] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"A-rsOJy6Nt5bu8V2TiFfbGa"}}
|
||||
[2026-03-03 18:26:34] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-03 18:26:34] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-03 18:26:34] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-03 18:26:34] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-03 18:40:46] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-03 18:40:46] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-03 18:40:47] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AVgNR8KDAo3MJZd7sUEmwOA"}}
|
||||
[2026-03-03 18:40:47] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-03 18:40:47] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-03 18:40:47] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-03 18:40:47] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-03 18:45:56] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-03 18:45:57] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-03 18:45:58] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"A2BA0V1lFNEweoVj828N08C"}}
|
||||
[2026-03-03 18:45:58] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-03 18:45:58] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-03 18:45:58] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-03 18:45:58] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-03 18:52:25] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-03 18:52:25] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-03 18:52:26] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"A9NoZ-fzHlsYz9LVztCvsTs"}}
|
||||
[2026-03-03 18:52:26] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-03 18:52:26] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-03 18:52:26] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-03 18:52:26] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-03 18:53:23] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-03 18:53:24] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-03 18:53:24] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-03 18:53:24] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-03 18:53:24] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AFgjiwRrmVTXzoPHLwKsnKn"}}
|
||||
[2026-03-03 18:53:24] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-03 18:53:25] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-07 12:50:23] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-07 12:50:23] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-07 12:50:24] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AcQVcLKIJwSqIoyn5edcq6N"}}
|
||||
[2026-03-07 12:50:24] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-07 12:50:24] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-07 12:50:24] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-07 12:50:24] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-09 19:02:27] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-09 19:02:27] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-09 19:02:28] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AOwAqoVcoD5OhMDtVtKEmCr"}}
|
||||
[2026-03-09 19:02:28] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-09 19:02:28] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-09 19:02:28] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-09 19:02:28] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-09 19:02:34] Request: GET /api/version/media-url.php?id=876668735219378 GET:{"id":"876668735219378"} POST:[]
|
||||
[2026-03-09 19:02:35] Auto-download failed for media 876668735219378: Graph API fetch failed for media 876668735219378
|
||||
[2026-03-09 19:02:35] Graph API request to https://graph.facebook.com/v22.0/876668735219378
|
||||
[2026-03-09 19:03:43] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-09 19:03:43] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-09 19:03:44] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"ADXyHWK69LBJb0Xcb5WF6YN"}}
|
||||
[2026-03-09 19:03:44] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-09 19:03:44] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-09 19:03:44] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-09 19:03:44] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-09 19:44:40] Request: GET /api/version/media-url.php?id=876668735219378 GET:{"id":"876668735219378"} POST:[]
|
||||
[2026-03-09 19:44:41] Auto-download failed for media 876668735219378: Graph API fetch failed for media 876668735219378
|
||||
[2026-03-09 19:44:41] Graph API request to https://graph.facebook.com/v22.0/876668735219378
|
||||
[2026-03-10 11:48:52] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-10 11:48:52] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-10 11:48:53] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AmeTveBUDoB7IYGuJQpKn_S"}}
|
||||
[2026-03-10 11:48:53] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-10 11:48:53] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-10 11:48:53] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-10 11:48:53] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-10 11:49:09] Request: GET /api/version/media-url.php?id=876668735219378 GET:{"id":"876668735219378"} POST:[]
|
||||
[2026-03-10 11:49:10] Auto-download failed for media 876668735219378: Graph API fetch failed for media 876668735219378
|
||||
[2026-03-10 11:49:10] Graph API request to https://graph.facebook.com/v22.0/876668735219378
|
||||
[2026-03-10 11:49:20] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-10 11:49:20] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-10 11:49:21] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AqqWUUrnY6r8ZIl70J0e6Og"}}
|
||||
[2026-03-10 11:49:21] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-10 11:49:21] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-10 11:49:21] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-10 11:49:21] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-10 11:58:05] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-10 11:58:05] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-10 11:58:06] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AV59Bbr9DFXNl7y039WL8dV"}}
|
||||
[2026-03-10 11:58:06] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-10 11:58:06] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-10 11:58:06] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-10 11:58:06] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-10 12:19:04] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-10 12:19:04] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-10 12:19:06] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AGWqv0bu7HvWrrjbR65TJIf"}}
|
||||
[2026-03-10 12:19:06] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-10 12:19:06] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-10 12:19:06] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-10 12:19:06] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-10 12:19:13] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-10 12:19:13] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-10 12:19:14] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AgIetbmT5l7HlIzACky9rEV"}}
|
||||
[2026-03-10 12:19:14] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-10 12:19:14] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-10 12:19:14] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-10 12:19:14] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-10 12:19:37] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-10 12:19:37] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-10 12:19:38] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-10 12:19:38] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-10 12:19:38] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AThpsMjn6_1g_sqRZBJrtHu"}}
|
||||
[2026-03-10 12:19:38] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-10 12:19:38] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-10 12:28:02] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-10 12:28:02] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-10 12:28:03] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"A1pX_IwbWh_KHKUuck-nTb7"}}
|
||||
[2026-03-10 12:28:03] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-10 12:28:04] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-10 12:28:04] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-10 12:28:04] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-10 13:22:57] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-10 13:22:57] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-10 13:22:57] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AwADPHo5iki123yn3HWL7YD"}}
|
||||
[2026-03-10 13:22:57] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-10 13:22:58] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-10 13:22:58] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-10 13:22:58] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-10 13:45:06] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-10 13:45:06] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-10 13:45:07] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"A5rBKn9_qO3AUr1NYK4npdP"}}
|
||||
[2026-03-10 13:45:07] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-10 13:45:07] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-10 13:45:07] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-10 13:45:07] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-10 16:35:00] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-10 16:35:00] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-10 16:35:01] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AZil5Jg5IUvgKBvNXuqNAgJ"}}
|
||||
[2026-03-10 16:35:01] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-10 16:35:01] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-10 16:35:01] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-10 16:35:01] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-10 16:35:41] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-10 16:35:41] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-10 16:35:42] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AhZK_sM5jxmWJyHR0SDg-S_"}}
|
||||
[2026-03-10 16:35:42] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-10 16:35:42] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-10 16:35:42] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-10 16:35:42] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-10 16:59:13] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-10 16:59:13] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-10 16:59:14] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"A9BtUEbjlzsjlLVBf--RVAP"}}
|
||||
[2026-03-10 16:59:14] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-10 16:59:14] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-10 16:59:14] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-10 16:59:14] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-10 16:59:18] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-10 16:59:18] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-10 16:59:18] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AndqVm9VvEWqTibjCIvpkQK"}}
|
||||
[2026-03-10 16:59:18] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-10 16:59:18] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-10 16:59:18] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-10 16:59:18] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-10 16:59:29] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-10 16:59:29] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-10 16:59:29] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"Am3mQzxQnonDMVVhrF4yGVP"}}
|
||||
[2026-03-10 16:59:29] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-10 16:59:29] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-10 16:59:29] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-10 16:59:29] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
[2026-03-10 18:13:02] Request: GET /api/version/media-url.php?id=1217156256734654 GET:{"id":"1217156256734654"} POST:[]
|
||||
[2026-03-10 18:13:02] Request: GET /api/version/media-url.php?url=https%3A%2F%2Flookaside.fbsbx.com%2Fwhatsapp_business%2Fattachments%2F%3Fmid%3D2371342336638440%26source%3Dwebhook%26ext%3D1769575796%26hash%3DARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA GET:{"url":"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA"} POST:[]
|
||||
[2026-03-10 18:13:02] Graph API fetch failed for mid 2371342336638440 - http: 400 - err: - resp: {"error":{"message":"Unsupported get request. Object with ID '2371342336638440' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https:\/\/developers.facebook.com\/docs\/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AHjV--ez4QSdPn8y8ecMc3O"}}
|
||||
[2026-03-10 18:13:02] Streaming Facebook media with Authorization: https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA
|
||||
[2026-03-10 18:13:02] streamRemoteFile failed: url=https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=2371342336638440&source=webhook&ext=1769575796&hash=ARndVKdw1p0CCx3_DpTblR2aOVkb_W5mbTqGFPSOK77cjA err= http=404
|
||||
[2026-03-10 18:13:02] Auto-download failed for media 1217156256734654: Graph API fetch failed for media 1217156256734654
|
||||
[2026-03-10 18:13:02] Graph API request to https://graph.facebook.com/v22.0/1217156256734654
|
||||
|
||||
Reference in New Issue
Block a user