up
This commit is contained in:
@@ -17,6 +17,17 @@ try {
|
||||
$dom = new Domicilio();
|
||||
$admin = adminId();
|
||||
|
||||
// ── Reprogramar ──
|
||||
if (!empty($datos['id']) && !empty($datos['reprogramar'])) {
|
||||
$id = (int)$datos['id'];
|
||||
$nuevaFecha = trim($datos['nueva_fecha'] ?? '');
|
||||
$nuevaHora = trim($datos['nueva_hora'] ?? '');
|
||||
$motivo = trim($datos['motivo'] ?? '');
|
||||
if (!$nuevaFecha) jsonError('nueva_fecha es obligatoria');
|
||||
$nuevoId = $dom->reprogramar($id, $nuevaFecha, $nuevaHora, $motivo, $admin);
|
||||
jsonOk(['id_origen' => $id, 'id_nuevo' => $nuevoId], 'Domicilio reprogramado correctamente');
|
||||
}
|
||||
|
||||
// Solo cambio de estado
|
||||
if (!empty($datos['id']) && !empty($datos['solo_estado'])) {
|
||||
$id = (int)$datos['id'];
|
||||
|
||||
@@ -163,6 +163,20 @@ class Domicilio {
|
||||
[$id]
|
||||
);
|
||||
|
||||
// Vínculo: domicilio origen (este fue reprogramado desde otro)
|
||||
if (!empty($dom['domicilio_origen_id'])) {
|
||||
$dom['origen_info'] = $this->db->fetch(
|
||||
"SELECT id, fecha_programada, hora_programada, estado FROM lab_domicilios WHERE id = ?",
|
||||
[(int)$dom['domicilio_origen_id']]
|
||||
);
|
||||
}
|
||||
|
||||
// Vínculo: domicilio(s) reprogramado(s) desde este
|
||||
$dom['reprogramaciones'] = $this->db->fetchAll(
|
||||
"SELECT id, fecha_programada, hora_programada, estado FROM lab_domicilios WHERE domicilio_origen_id = ? ORDER BY id ASC",
|
||||
[$id]
|
||||
);
|
||||
|
||||
return $dom;
|
||||
}
|
||||
|
||||
@@ -217,6 +231,63 @@ class Domicilio {
|
||||
return $ok > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reprogramar un domicilio:
|
||||
* 1. Marca el original como 'reprogramado' con fecha_reprogramada.
|
||||
* 2. Clona el domicilio para la nueva fecha/hora.
|
||||
* 3. Vincula el clon con domicilio_origen_id.
|
||||
*
|
||||
* @return int ID del nuevo domicilio creado.
|
||||
*/
|
||||
public function reprogramar(
|
||||
int $idOrigen,
|
||||
string $nuevaFecha,
|
||||
string $nuevaHora = '',
|
||||
string $motivo = '',
|
||||
?int $adminId = null
|
||||
): int {
|
||||
// 1. Obtener datos del original
|
||||
$origen = $this->db->fetch(
|
||||
'SELECT * FROM lab_domicilios WHERE id = ?', [$idOrigen]
|
||||
);
|
||||
if (!$origen) {
|
||||
throw new \RuntimeException('Domicilio no encontrado');
|
||||
}
|
||||
|
||||
// 2. Marcar original como reprogramado
|
||||
$extrasOrigen = [
|
||||
'fecha_reprogramada' => $nuevaFecha,
|
||||
];
|
||||
if ($motivo) $extrasOrigen['motivo_cancelacion'] = $motivo;
|
||||
$this->cambiarEstado($idOrigen, 'reprogramado', $adminId, $extrasOrigen);
|
||||
|
||||
// 3. Clonar campos relevantes para el nuevo domicilio
|
||||
$campos = $this->filtrarCampos($origen);
|
||||
// Resetear campos operativos del original
|
||||
unset(
|
||||
$campos['estado'], $campos['motivo_cancelacion'],
|
||||
$campos['fecha_reprogramada'], $campos['hora_llegada'],
|
||||
$campos['hora_salida'], $campos['observaciones'],
|
||||
$campos['muestras_tomadas'], $campos['pago_estado'],
|
||||
$campos['pago_modo'], $campos['pago_monto'],
|
||||
$campos['pago_fecha'], $campos['pago_notas'],
|
||||
$campos['pago_registrado_por'], $campos['temperatura_inicio'],
|
||||
$campos['temperatura_salida'], $campos['domicilio_origen_id']
|
||||
);
|
||||
$campos['fecha_programada'] = $nuevaFecha;
|
||||
$campos['hora_programada'] = $nuevaHora ?: null;
|
||||
$campos['estado'] = 'programado';
|
||||
$campos['domicilio_origen_id']= $idOrigen;
|
||||
$campos['creado_por'] = $adminId;
|
||||
|
||||
$nuevoId = (int)$this->db->insert('lab_domicilios', $campos);
|
||||
$this->log->registrar($adminId, 'domicilios', 'reprogramar', $nuevoId, [
|
||||
'origen_id' => $idOrigen,
|
||||
'nueva_fecha' => $nuevaFecha,
|
||||
]);
|
||||
return $nuevoId;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// Agenda del día
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
@@ -279,6 +350,7 @@ class Domicilio {
|
||||
'observaciones', 'muestras_tomadas', 'notas_admin',
|
||||
'seguro_nombre', 'autorizacion', 'copago_laboratorio',
|
||||
'valor_domicilio', 'valor_copago',
|
||||
'domicilio_origen_id',
|
||||
// pago
|
||||
'pago_estado', 'pago_modo', 'pago_monto', 'pago_fecha',
|
||||
'pago_notas', 'pago_registrado_por',
|
||||
|
||||
+87
-1
@@ -520,6 +520,41 @@ $domIdParam = (int)($_GET['id'] ?? 0);
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ═══════════════ MODAL: Reprogramar Domicilio ═══════════════ -->
|
||||
<div class="modal fade" id="modalReprogramar" tabindex="-1">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header py-2" style="background:#6f42c1;color:#fff">
|
||||
<h6 class="modal-title mb-0"><i class="fas fa-calendar-alt me-1"></i>Reprogramar domicilio</h6>
|
||||
<button class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="repr-dom-id">
|
||||
<div class="mb-3">
|
||||
<label class="form-label small fw-semibold">Nueva fecha <span class="text-danger">*</span></label>
|
||||
<input type="date" class="form-control form-control-sm" id="repr-fecha">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small fw-semibold">Nueva hora</label>
|
||||
<input type="time" class="form-control form-control-sm" id="repr-hora">
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label class="form-label small fw-semibold">Motivo / nota</label>
|
||||
<textarea class="form-control form-control-sm" id="repr-motivo" rows="2"
|
||||
placeholder="Ej: Paciente solicitó cambio…"></textarea>
|
||||
</div>
|
||||
<div id="repr-error" class="text-danger small d-none">Debes ingresar la nueva fecha.</div>
|
||||
</div>
|
||||
<div class="modal-footer py-2">
|
||||
<button class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Cancelar</button>
|
||||
<button class="btn btn-sm text-white" style="background:#6f42c1" onclick="confirmarReprogramar()">
|
||||
<i class="fas fa-calendar-check me-1"></i>Reprogramar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Asignar / Reasignar Enfermero -->
|
||||
<div class="modal fade" id="modalAsignarEnf" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
@@ -768,6 +803,13 @@ async function verDomicilio(id) {
|
||||
en_camino: [['en_domicilio','En domicilio','warning']],
|
||||
en_domicilio:[['completado','Completar','success']],
|
||||
};
|
||||
// Reprogramar disponible en estados abiertos (excepto en camino / en domicilio)
|
||||
const puedeReprogramar = ['programado','confirmado'].includes(dom.estado);
|
||||
const btnRepr = puedeReprogramar
|
||||
? `<button class="btn btn-sm" style="background:#6f42c1;color:#fff" onclick="abrirReprogramar(${dom.id})">
|
||||
<i class="fas fa-calendar-alt me-1"></i>Reprogramar
|
||||
</button>`
|
||||
: '';
|
||||
const btns = (SIGUIENTES[dom.estado]||[]).map(([e,lbl,col]) =>
|
||||
`<button class="btn btn-sm btn-${col}" onclick="cambiarEstado(${dom.id},'${e}')">
|
||||
<i class="fas fa-arrow-right me-1"></i>${lbl}
|
||||
@@ -824,7 +866,23 @@ async function verDomicilio(id) {
|
||||
<!-- Orden médica -->
|
||||
${renderOrdenesDetail(dom)}
|
||||
<!-- Botones de flujo -->
|
||||
<div class="d-flex gap-2 flex-wrap">${btns}</div>
|
||||
<div class="d-flex gap-2 flex-wrap">${btns}${btnRepr}</div>
|
||||
<!-- Vínculos reprogramación -->
|
||||
${dom.domicilio_origen_id ? `
|
||||
<div class="alert alert-warning py-2 small mt-2 mb-0">
|
||||
<i class="fas fa-history me-1"></i>
|
||||
Reprogramado desde domicilio
|
||||
<a href="#" onclick="event.preventDefault();verDomicilio(${dom.domicilio_origen_id})" class="fw-semibold">#${dom.domicilio_origen_id}</a>
|
||||
${dom.origen_info ? `(${esc(dom.origen_info.fecha_programada)})` : ''}
|
||||
</div>` : ''}
|
||||
${dom.reprogramaciones && dom.reprogramaciones.length ? `
|
||||
<div class="alert alert-info py-2 small mt-2 mb-0">
|
||||
<i class="fas fa-calendar-check me-1"></i>
|
||||
Reprogramado a:
|
||||
${dom.reprogramaciones.map(r =>
|
||||
`<a href="#" onclick="event.preventDefault();verDomicilio(${r.id})" class="fw-semibold">#${r.id}</a> (${esc(r.fecha_programada)})`
|
||||
).join(', ')}
|
||||
</div>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-3">
|
||||
@@ -1106,6 +1164,34 @@ async function confirmarAsignacion() {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Reprogramar domicilio ───────────────────────────────────
|
||||
let _reprModal = null;
|
||||
function abrirReprogramar(id) {
|
||||
document.getElementById('repr-dom-id').value = id;
|
||||
document.getElementById('repr-fecha').value = '';
|
||||
document.getElementById('repr-hora').value = _domActual?.hora_programada?.slice(0,5) || '';
|
||||
document.getElementById('repr-motivo').value = '';
|
||||
document.getElementById('repr-error').classList.add('d-none');
|
||||
if (!_reprModal) _reprModal = new bootstrap.Modal('#modalReprogramar');
|
||||
_reprModal.show();
|
||||
}
|
||||
async function confirmarReprogramar() {
|
||||
const id = +document.getElementById('repr-dom-id').value;
|
||||
const fecha = document.getElementById('repr-fecha').value;
|
||||
const hora = document.getElementById('repr-hora').value;
|
||||
const motivo = document.getElementById('repr-motivo').value.trim();
|
||||
if (!fecha) { document.getElementById('repr-error').classList.remove('d-none'); return; }
|
||||
_reprModal.hide();
|
||||
const r = await fetch('api/lab/save_domicilio.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id, reprogramar: true, nueva_fecha: fecha, nueva_hora: hora, motivo }),
|
||||
});
|
||||
const d = await r.json();
|
||||
mostrarToast(d.success ? d.message : (d.error || 'Error'), d.success ? 'success' : 'danger');
|
||||
if (d.success) { cargarLista(paginaActual); verDomicilio(id); }
|
||||
}
|
||||
|
||||
// ── Cambio de estado ───────────────────────────────────────────────────────
|
||||
async function cambiarEstado(id, estado) {
|
||||
if (!confirm(`¿Cambiar estado a "${estado}"?`)) return;
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
-- ============================================================
|
||||
-- Migration: 20260408_lab_domicilio_origen_id
|
||||
-- Vincula un domicilio reprogramado con su domicilio origen
|
||||
-- ============================================================
|
||||
|
||||
ALTER TABLE `lab_domicilios`
|
||||
ADD COLUMN `domicilio_origen_id` INT(11) DEFAULT NULL
|
||||
COMMENT 'FK al domicilio original del que fue reprogramado'
|
||||
AFTER `id`,
|
||||
ADD KEY `idx_dom_origen` (`domicilio_origen_id`),
|
||||
ADD CONSTRAINT `fk_dom_origen`
|
||||
FOREIGN KEY (`domicilio_origen_id`)
|
||||
REFERENCES `lab_domicilios` (`id`)
|
||||
ON DELETE SET NULL;
|
||||
Reference in New Issue
Block a user