feat: 6 nuevas funcionalidades - notas obligatorias turno, reporte enfermero, plantilla WhatsApp, adjuntar orden modal, roles solo lectura, fix valores copago
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* API — Bloquear / Desbloquear usuario de WhatsApp
|
||||
* POST { user_id: int, blocked: bool }
|
||||
* Cambia users.status entre 'active' y 'blocked'.
|
||||
* El BotService omite cualquier mensaje entrante de usuarios bloqueados.
|
||||
*/
|
||||
require_once '../config/config.php';
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
requireAuthentication();
|
||||
|
||||
try {
|
||||
$input = json_decode(file_get_contents('php://input'), true) ?: [];
|
||||
$userId = isset($input['user_id']) ? intval($input['user_id']) : 0;
|
||||
if (!isset($input['blocked'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'error' => 'user_id and blocked are required']);
|
||||
exit;
|
||||
}
|
||||
$blocked = (bool)$input['blocked'];
|
||||
|
||||
if ($userId <= 0) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'error' => 'Invalid user_id']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$db = Database::getInstance();
|
||||
$status = $blocked ? 'blocked' : 'active';
|
||||
$db->update('users', ['status' => $status], 'id = :id', ['id' => $userId]);
|
||||
|
||||
echo json_encode(['success' => true, 'blocked' => $blocked, 'status' => $status]);
|
||||
} catch (Exception $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
}
|
||||
@@ -26,6 +26,7 @@ try {
|
||||
u.id as user_id,
|
||||
u.phone_number,
|
||||
COALESCE(u.name, u.phone_number) as name,
|
||||
u.status as user_status,
|
||||
c.content as last_message,
|
||||
c.direction as last_direction,
|
||||
c.message_type as last_message_type,
|
||||
@@ -43,7 +44,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, u.terms_pending, u.terms_accepted_at
|
||||
GROUP BY u.id, u.phone_number, u.name, u.status, 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"
|
||||
);
|
||||
@@ -59,6 +60,7 @@ try {
|
||||
'user_id' => intval($conv['user_id']),
|
||||
'phone_number' => $conv['phone_number'],
|
||||
'name' => $conv['name'],
|
||||
'user_status' => $conv['user_status'] ?? 'active',
|
||||
'last_message' => $conv['last_message'] ?? '',
|
||||
'last_direction' => $conv['last_direction'] ?? 'incoming',
|
||||
'last_message_type' => $conv['last_message_type'] ?? 'text',
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/**
|
||||
* API: Reporte de domicilios agrupado por enfermero, año y mes.
|
||||
*
|
||||
* GET params (todos opcionales):
|
||||
* anio Año a filtrar (ej. 2026). Si se omite, devuelve todos.
|
||||
* mes Mes 1-12. Sólo funciona junto con anio.
|
||||
* enfermera_id ID de la enfermera. Si se omite, devuelve todas.
|
||||
*/
|
||||
require_once __DIR__ . '/../../config/config.php';
|
||||
require_once __DIR__ . '/../../classes/Database.php';
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('X-Content-Type-Options: nosniff');
|
||||
|
||||
requireAuthentication();
|
||||
|
||||
$db = Database::getInstance();
|
||||
|
||||
$anio = isset($_GET['anio']) && ctype_digit($_GET['anio']) ? (int)$_GET['anio'] : null;
|
||||
$mes = isset($_GET['mes']) && ctype_digit($_GET['mes']) ? (int)$_GET['mes'] : null;
|
||||
$enfermeraId = isset($_GET['enfermera_id'])&& ctype_digit($_GET['enfermera_id']) ? (int)$_GET['enfermera_id']: null;
|
||||
|
||||
$wheres = [];
|
||||
$params = [];
|
||||
|
||||
if ($anio !== null) {
|
||||
$wheres[] = 'YEAR(d.fecha_programada) = ?';
|
||||
$params[] = $anio;
|
||||
if ($mes !== null) {
|
||||
$wheres[] = 'MONTH(d.fecha_programada) = ?';
|
||||
$params[] = $mes;
|
||||
}
|
||||
}
|
||||
|
||||
if ($enfermeraId !== null) {
|
||||
$wheres[] = 'e.id = ?';
|
||||
$params[] = $enfermeraId;
|
||||
}
|
||||
|
||||
$where = $wheres ? 'WHERE ' . implode(' AND ', $wheres) : '';
|
||||
|
||||
$filas = $db->fetchAll(
|
||||
"SELECT
|
||||
e.id AS enfermera_id,
|
||||
e.nombre_completo AS enfermera,
|
||||
YEAR(d.fecha_programada) AS anio,
|
||||
MONTH(d.fecha_programada) AS mes,
|
||||
COUNT(*) AS total,
|
||||
SUM(d.estado = 'completado') AS completados,
|
||||
SUM(d.estado = 'cancelado') AS cancelados,
|
||||
SUM(d.estado NOT IN ('completado','cancelado')) AS en_proceso
|
||||
FROM lab_domicilios d
|
||||
JOIN lab_asignaciones a ON a.domicilio_id = d.id
|
||||
AND a.estado NOT IN ('liberada')
|
||||
JOIN lab_enfermeras e ON e.id = a.enfermera_id
|
||||
$where
|
||||
GROUP BY e.id, YEAR(d.fecha_programada), MONTH(d.fecha_programada)
|
||||
ORDER BY e.nombre_completo, YEAR(d.fecha_programada) DESC, MONTH(d.fecha_programada) DESC",
|
||||
$params
|
||||
);
|
||||
|
||||
$meses_es = [
|
||||
1=>'Ene',2=>'Feb',3=>'Mar',4=>'Abr',5=>'May',6=>'Jun',
|
||||
7=>'Jul',8=>'Ago',9=>'Sep',10=>'Oct',11=>'Nov',12=>'Dic',
|
||||
];
|
||||
|
||||
foreach ($filas as &$f) {
|
||||
$t = (int)$f['total'];
|
||||
$f['tasa_pct'] = $t ? round((int)$f['completados'] / $t * 100) : 0;
|
||||
$f['mes_nombre'] = $meses_es[(int)$f['mes']] ?? $f['mes'];
|
||||
}
|
||||
unset($f);
|
||||
|
||||
// Lista de enfermeras para el selector del filtro
|
||||
$enfermeras = $db->fetchAll(
|
||||
"SELECT id, nombre_completo FROM lab_enfermeras WHERE activa = 1 ORDER BY nombre_completo"
|
||||
);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'filas' => $filas,
|
||||
'enfermeras' => $enfermeras,
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
Reference in New Issue
Block a user