feat: sistema de pagos domicilios — cobro enfermero y estado pago admin
- database/07_add_pago_domicilio.sql: 6 columnas nuevas en lab_domicilios (pago_estado ENUM, pago_modo, pago_monto, pago_fecha, pago_notas, pago_registrado_por) - Domicilio::filtrarCampos(): permite guardar campos de pago vía actualizar() - Enfermera::agenda(): incluye valor_domicilio, valor_copago, pago_estado, pago_modo, pago_monto, pago_notas - api/lab/registrar_pago.php: endpoint POST para registrar/actualizar pago del domicilio - enfermero_portal.php: bloque cobro en card, modal registrar pago (efectivo/transferencia/exento), objeto pagoModal JS - lab_domicilios.php: badge pago ⏳/✅/🔵 en fila tabla, sección pago detallada en panel lateral
This commit is contained in:
@@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* POST /api/lab/registrar_pago.php
|
||||||
|
* Registra el pago de un domicilio por parte del cliente.
|
||||||
|
* Solo puede llamarse desde el portal del enfermero o por un admin.
|
||||||
|
*
|
||||||
|
* Body JSON:
|
||||||
|
* {
|
||||||
|
* domicilio_id: int,
|
||||||
|
* pago_estado: 'pagado' | 'exento' | 'pendiente',
|
||||||
|
* pago_modo: 'efectivo' | 'transferencia' | 'otro', (requerido si pagado)
|
||||||
|
* pago_monto: float, (requerido si pagado)
|
||||||
|
* pago_notas: string|null
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
require_once __DIR__ . '/_helpers.php';
|
||||||
|
requireMethod('POST');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$datos = inputJson();
|
||||||
|
|
||||||
|
$domId = (int)($datos['domicilio_id'] ?? 0);
|
||||||
|
$estado = $datos['pago_estado'] ?? '';
|
||||||
|
|
||||||
|
if (!$domId) jsonError('domicilio_id requerido');
|
||||||
|
if (!in_array($estado, ['pagado', 'exento', 'pendiente'], true))
|
||||||
|
jsonError('pago_estado inválido (pagado|exento|pendiente)');
|
||||||
|
|
||||||
|
if ($estado === 'pagado') {
|
||||||
|
if (empty($datos['pago_modo']) || !in_array($datos['pago_modo'], ['efectivo','transferencia','otro'], true))
|
||||||
|
jsonError('pago_modo inválido (efectivo|transferencia|otro)');
|
||||||
|
if (!isset($datos['pago_monto']) || (float)$datos['pago_monto'] <= 0)
|
||||||
|
jsonError('pago_monto debe ser mayor a 0');
|
||||||
|
}
|
||||||
|
|
||||||
|
$adminId = adminId();
|
||||||
|
$dom = new Domicilio();
|
||||||
|
|
||||||
|
// Verificar que existe
|
||||||
|
$exist = Database::getInstance()->fetch(
|
||||||
|
'SELECT id, pago_estado FROM lab_domicilios WHERE id = ?', [$domId]
|
||||||
|
);
|
||||||
|
if (!$exist) jsonError("Domicilio #$domId no encontrado");
|
||||||
|
|
||||||
|
$campos = [
|
||||||
|
'pago_estado' => $estado,
|
||||||
|
'pago_modo' => ($estado === 'pagado') ? ($datos['pago_modo'] ?? null) : null,
|
||||||
|
'pago_monto' => ($estado === 'pagado') ? ((float)$datos['pago_monto']) : null,
|
||||||
|
'pago_fecha' => ($estado === 'pagado') ? date('Y-m-d H:i:s') : null,
|
||||||
|
'pago_notas' => !empty($datos['pago_notas']) ? trim($datos['pago_notas']) : null,
|
||||||
|
'pago_registrado_por' => $adminId,
|
||||||
|
];
|
||||||
|
|
||||||
|
$dom->actualizar($domId, $campos, $adminId);
|
||||||
|
|
||||||
|
jsonOk([
|
||||||
|
'domicilio_id' => $domId,
|
||||||
|
'pago_estado' => $estado,
|
||||||
|
], 'Pago registrado correctamente');
|
||||||
|
|
||||||
|
} catch (InvalidArgumentException $e) {
|
||||||
|
jsonError($e->getMessage());
|
||||||
|
} catch (Exception $e) {
|
||||||
|
jsonError($e->getMessage(), 500);
|
||||||
|
}
|
||||||
@@ -246,6 +246,9 @@ class Domicilio {
|
|||||||
'observaciones', 'muestras_tomadas', 'notas_admin',
|
'observaciones', 'muestras_tomadas', 'notas_admin',
|
||||||
'seguro_nombre', 'autorizacion', 'copago_laboratorio',
|
'seguro_nombre', 'autorizacion', 'copago_laboratorio',
|
||||||
'valor_domicilio', 'valor_copago',
|
'valor_domicilio', 'valor_copago',
|
||||||
|
// pago
|
||||||
|
'pago_estado', 'pago_modo', 'pago_monto', 'pago_fecha',
|
||||||
|
'pago_notas', 'pago_registrado_por',
|
||||||
];
|
];
|
||||||
$campos = array_intersect_key($datos, array_flip($permitidos));
|
$campos = array_intersect_key($datos, array_flip($permitidos));
|
||||||
|
|
||||||
|
|||||||
@@ -107,6 +107,14 @@ class Enfermera {
|
|||||||
d.tipo_cliente,
|
d.tipo_cliente,
|
||||||
d.seguro_nombre,
|
d.seguro_nombre,
|
||||||
d.orden_id,
|
d.orden_id,
|
||||||
|
d.valor_domicilio,
|
||||||
|
d.valor_copago,
|
||||||
|
d.copago_laboratorio,
|
||||||
|
d.autorizacion,
|
||||||
|
d.pago_estado,
|
||||||
|
d.pago_modo,
|
||||||
|
d.pago_monto,
|
||||||
|
d.pago_notas,
|
||||||
p.id AS paciente_id,
|
p.id AS paciente_id,
|
||||||
p.nombre_completo AS paciente_nombre,
|
p.nombre_completo AS paciente_nombre,
|
||||||
p.telefono AS paciente_telefono,
|
p.telefono AS paciente_telefono,
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
-- ============================================================
|
||||||
|
-- Migration: 07_add_pago_domicilio
|
||||||
|
-- Agrega campos de pago del cliente a lab_domicilios
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
ALTER TABLE `lab_domicilios`
|
||||||
|
ADD COLUMN IF NOT EXISTS `pago_estado` ENUM('pendiente','pagado','exento') NOT NULL DEFAULT 'pendiente'
|
||||||
|
COMMENT 'Estado del pago del cliente: pendiente / pagado / exento'
|
||||||
|
AFTER `valor_copago`,
|
||||||
|
|
||||||
|
ADD COLUMN IF NOT EXISTS `pago_modo` ENUM('efectivo','transferencia','otro') DEFAULT NULL
|
||||||
|
COMMENT 'Medio de pago usado por el cliente'
|
||||||
|
AFTER `pago_estado`,
|
||||||
|
|
||||||
|
ADD COLUMN IF NOT EXISTS `pago_monto` DECIMAL(12,2) DEFAULT NULL
|
||||||
|
COMMENT 'Monto efectivamente cobrado al cliente'
|
||||||
|
AFTER `pago_modo`,
|
||||||
|
|
||||||
|
ADD COLUMN IF NOT EXISTS `pago_fecha` DATETIME DEFAULT NULL
|
||||||
|
COMMENT 'Fecha y hora en que se registró el pago'
|
||||||
|
AFTER `pago_monto`,
|
||||||
|
|
||||||
|
ADD COLUMN IF NOT EXISTS `pago_notas` VARCHAR(255) DEFAULT NULL
|
||||||
|
COMMENT 'Observaciones del pago (referencia transferencia, etc.)'
|
||||||
|
AFTER `pago_fecha`,
|
||||||
|
|
||||||
|
ADD COLUMN IF NOT EXISTS `pago_registrado_por` INT DEFAULT NULL
|
||||||
|
COMMENT 'FK al enfermero/admin que registró el pago'
|
||||||
|
AFTER `pago_notas`;
|
||||||
|
|
||||||
|
-- Índice para consultas rápidas por estado de pago
|
||||||
|
ALTER TABLE `lab_domicilios`
|
||||||
|
ADD INDEX IF NOT EXISTS `idx_pago_estado` (`pago_estado`);
|
||||||
@@ -110,6 +110,13 @@ $hoy = date('Y-m-d');
|
|||||||
border-bottom:1px solid #f0f0f0; }
|
border-bottom:1px solid #f0f0f0; }
|
||||||
.sugerencias-pac .item:hover { background:#f0f4ff; }
|
.sugerencias-pac .item:hover { background:#f0f4ff; }
|
||||||
.sugerencias-pac .item:last-child { border-bottom:none; }
|
.sugerencias-pac .item:last-child { border-bottom:none; }
|
||||||
|
|
||||||
|
/* ── Pago ── */
|
||||||
|
.pago-badge-pendiente { background:#fff3cd; color:#664d03; border:1px solid #ffc107; }
|
||||||
|
.pago-badge-pagado { background:#d1fae5; color:#065f46; border:1px solid #34d399; }
|
||||||
|
.pago-badge-exento { background:#e0e7ff; color:#3730a3; border:1px solid #818cf8; }
|
||||||
|
.cobro-box { background:#f0fdf4; border:1px solid #86efac; border-radius:8px; padding:.6rem .9rem; }
|
||||||
|
.cobro-box.sin-cobro { background:#f9fafb; border-color:#e5e7eb; color:#9ca3af; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -242,6 +249,74 @@ $hoy = date('Y-m-d');
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════ MODAL: Registrar Pago ══════════════════ -->
|
||||||
|
<div class="modal fade" id="modalPago" tabindex="-1">
|
||||||
|
<div class="modal-dialog modal-sm">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header py-2" style="background:#065f46;color:#fff">
|
||||||
|
<h6 class="modal-title mb-0"><i class="fas fa-money-bill-wave me-1"></i>Registrar Pago</h6>
|
||||||
|
<button class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<input type="hidden" id="pago-dom-id">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label small fw-semibold">Estado del pago</label>
|
||||||
|
<div class="d-flex gap-2 flex-wrap">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="radio" name="pago-estado"
|
||||||
|
id="pago-pagado" value="pagado" checked
|
||||||
|
onchange="pagoModal.toggleModo()">
|
||||||
|
<label class="form-check-label small" for="pago-pagado">💵 Pagado</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="radio" name="pago-estado"
|
||||||
|
id="pago-exento" value="exento"
|
||||||
|
onchange="pagoModal.toggleModo()">
|
||||||
|
<label class="form-check-label small" for="pago-exento">🔵 Exento</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="radio" name="pago-estado"
|
||||||
|
id="pago-pendiente" value="pendiente"
|
||||||
|
onchange="pagoModal.toggleModo()">
|
||||||
|
<label class="form-check-label small" for="pago-pendiente">⏳ Pendiente</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="pago-campos-pago">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label small fw-semibold">Modo de pago <span class="text-danger">*</span></label>
|
||||||
|
<select class="form-select form-select-sm" id="pago-modo">
|
||||||
|
<option value="efectivo">💵 Efectivo</option>
|
||||||
|
<option value="transferencia">📲 Transferencia</option>
|
||||||
|
<option value="otro">📋 Otro</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label small fw-semibold">Monto cobrado <span class="text-danger">*</span></label>
|
||||||
|
<div class="input-group input-group-sm">
|
||||||
|
<span class="input-group-text">$</span>
|
||||||
|
<input type="number" class="form-control" id="pago-monto"
|
||||||
|
placeholder="0" min="0" step="1000">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="form-label small">Notas / referencia</label>
|
||||||
|
<input type="text" class="form-control form-control-sm" id="pago-notas"
|
||||||
|
placeholder="Ej: nequi ref #123456">
|
||||||
|
</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:#065f46"
|
||||||
|
onclick="pagoModal.guardar()">
|
||||||
|
<i class="fas fa-save me-1"></i>Guardar pago
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
const ENFERMERA_ID = <?= (int)$enfId ?>;
|
const ENFERMERA_ID = <?= (int)$enfId ?>;
|
||||||
@@ -341,6 +416,49 @@ const portal = {
|
|||||||
`<span class="se-chip">${esc(se.descripcion)}</span>`
|
`<span class="se-chip">${esc(se.descripcion)}</span>`
|
||||||
).join(' ');
|
).join(' ');
|
||||||
|
|
||||||
|
// ── Bloque de cobro ─────────────────────────────────────────────
|
||||||
|
const totalCobro = (parseFloat(item.valor_domicilio)||0) + (parseFloat(item.valor_copago)||0);
|
||||||
|
const hayCobro = totalCobro > 0;
|
||||||
|
const PAGO_LABEL = {
|
||||||
|
pendiente: { cls:'pago-badge-pendiente', icon:'⏳', txt:'Pago pendiente' },
|
||||||
|
pagado: { cls:'pago-badge-pagado', icon:'✅', txt:'Pagado' },
|
||||||
|
exento: { cls:'pago-badge-exento', icon:'🔵', txt:'Exento de pago' },
|
||||||
|
};
|
||||||
|
const pagoEst = item.pago_estado || 'pendiente';
|
||||||
|
const pagoInfo = PAGO_LABEL[pagoEst] || PAGO_LABEL.pendiente;
|
||||||
|
const MODO_LABEL = { efectivo:'💵 Efectivo', transferencia:'📲 Transferencia', otro:'📋 Otro' };
|
||||||
|
|
||||||
|
const cobroHtml = `
|
||||||
|
<div class="cobro-box ${hayCobro ? '' : 'sin-cobro'} mt-2 mb-2">
|
||||||
|
${hayCobro ? `
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-1">
|
||||||
|
<span class="fw-semibold small"><i class="fas fa-cash-register me-1 text-success"></i>Cobro al cliente</span>
|
||||||
|
<span class="badge rounded-pill ${pagoInfo.cls} small px-2">${pagoInfo.icon} ${pagoInfo.txt}</span>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex flex-wrap gap-2 small mb-1">
|
||||||
|
${item.valor_domicilio ? `<span>Domicilio: <strong>$${Number(item.valor_domicilio).toLocaleString('es-CO')}</strong></span>` : ''}
|
||||||
|
${item.valor_copago ? `<span>Copago: <strong>$${Number(item.valor_copago).toLocaleString('es-CO')}</strong></span>` : ''}
|
||||||
|
<span class="fw-bold text-success">Total: <strong>$${totalCobro.toLocaleString('es-CO')}</strong></span>
|
||||||
|
</div>
|
||||||
|
${item.pago_estado === 'pagado' && item.pago_modo ? `
|
||||||
|
<div class="small text-success">
|
||||||
|
${MODO_LABEL[item.pago_modo] || item.pago_modo}
|
||||||
|
${item.pago_monto ? ` · $${Number(item.pago_monto).toLocaleString('es-CO')}` : ''}
|
||||||
|
${item.pago_notas ? ` · <em>${esc(item.pago_notas)}</em>` : ''}
|
||||||
|
</div>` : ''}
|
||||||
|
${item.pago_estado !== 'pagado' && item.pago_estado !== 'exento' ? `
|
||||||
|
<button class="btn btn-sm mt-2 text-white w-100" style="background:#065f46;font-size:.78rem"
|
||||||
|
onclick="pagoModal.abrir(${item.domicilio_id}, ${totalCobro})">
|
||||||
|
<i class="fas fa-money-bill-wave me-1"></i>Registrar pago
|
||||||
|
</button>` : `
|
||||||
|
<button class="btn btn-sm btn-outline-secondary mt-2 w-100" style="font-size:.75rem"
|
||||||
|
onclick="pagoModal.abrir(${item.domicilio_id}, ${totalCobro})">
|
||||||
|
<i class="fas fa-edit me-1"></i>Editar pago
|
||||||
|
</button>`}
|
||||||
|
` : `<span class="small"><i class="fas fa-info-circle me-1"></i>Sin cobro registrado para este servicio</span>`}
|
||||||
|
</div>`;
|
||||||
|
// ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
const btnsAccion = trans.map(t =>
|
const btnsAccion = trans.map(t =>
|
||||||
`<button class="btn btn-${t.color} btn-accion"
|
`<button class="btn btn-${t.color} btn-accion"
|
||||||
onclick="portal.actualizarEstado(${item.domicilio_id},'${t.estado}')">
|
onclick="portal.actualizarEstado(${item.domicilio_id},'${t.estado}')">
|
||||||
@@ -412,6 +530,9 @@ const portal = {
|
|||||||
? `<div class="small mb-2"><span class="badge bg-info text-dark"><i class="fas fa-shield-alt me-1"></i>Seguro${item.seguro_nombre ? ': ' + esc(item.seguro_nombre) : ''}</span></div>`
|
? `<div class="small mb-2"><span class="badge bg-info text-dark"><i class="fas fa-shield-alt me-1"></i>Seguro${item.seguro_nombre ? ': ' + esc(item.seguro_nombre) : ''}</span></div>`
|
||||||
: ''}
|
: ''}
|
||||||
|
|
||||||
|
<!-- Cobro y pago -->
|
||||||
|
${cobroHtml}
|
||||||
|
|
||||||
<!-- Orden médica (imagen) -->
|
<!-- Orden médica (imagen) -->
|
||||||
${item.orden_local_file ? `
|
${item.orden_local_file ? `
|
||||||
<div class="mt-2 mb-2">
|
<div class="mt-2 mb-2">
|
||||||
@@ -1030,6 +1151,87 @@ const formEnvio = {
|
|||||||
} catch(e) { alert('No se pudo copiar'); }
|
} catch(e) { alert('No se pudo copiar'); }
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ══════════════════════════════════════════════════════════
|
||||||
|
// OBJETO: pagoModal — Gestión del modal de registro de pago
|
||||||
|
// ══════════════════════════════════════════════════════════
|
||||||
|
const pagoModal = {
|
||||||
|
_bsModal: null,
|
||||||
|
|
||||||
|
// Abrir modal pre-cargado con domicilio y monto sugerido
|
||||||
|
abrir(domId, totalSugerido = 0) {
|
||||||
|
document.getElementById('pago-dom-id').value = domId;
|
||||||
|
document.getElementById('pago-monto').value = totalSugerido > 0 ? totalSugerido : '';
|
||||||
|
document.getElementById('pago-notas').value = '';
|
||||||
|
document.getElementById('pago-modo').value = 'efectivo';
|
||||||
|
|
||||||
|
// Recuperar estado actual desde la agenda cargada
|
||||||
|
const item = (portal._agenda || []).find(d => d.domicilio_id == domId);
|
||||||
|
const est = item ? (item.pago_estado || 'pendiente') : 'pendiente';
|
||||||
|
document.querySelector(`input[name="pago-estado"][value="${est}"]`).checked = true;
|
||||||
|
|
||||||
|
this.toggleModo();
|
||||||
|
|
||||||
|
if (!this._bsModal) {
|
||||||
|
this._bsModal = new bootstrap.Modal(document.getElementById('modalPago'));
|
||||||
|
}
|
||||||
|
this._bsModal.show();
|
||||||
|
},
|
||||||
|
|
||||||
|
// Mostrar/ocultar campos de modo y monto según estado
|
||||||
|
toggleModo() {
|
||||||
|
const est = document.querySelector('input[name="pago-estado"]:checked')?.value;
|
||||||
|
document.getElementById('pago-campos-pago').style.display =
|
||||||
|
est === 'pagado' ? '' : 'none';
|
||||||
|
},
|
||||||
|
|
||||||
|
// Guardar pago vía API
|
||||||
|
async guardar() {
|
||||||
|
const domId = document.getElementById('pago-dom-id').value;
|
||||||
|
const estado = document.querySelector('input[name="pago-estado"]:checked')?.value;
|
||||||
|
const modo = document.getElementById('pago-modo').value;
|
||||||
|
const monto = parseFloat(document.getElementById('pago-monto').value) || 0;
|
||||||
|
const notas = document.getElementById('pago-notas').value.trim();
|
||||||
|
|
||||||
|
if (!estado) { alert('Selecciona el estado del pago.'); return; }
|
||||||
|
if (estado === 'pagado' && (!modo || monto <= 0)) {
|
||||||
|
alert('Para marcar como pagado debes ingresar el modo y el monto cobrado.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const payload = { domicilio_id: domId, pago_estado: estado };
|
||||||
|
if (estado === 'pagado') {
|
||||||
|
payload.pago_modo = modo;
|
||||||
|
payload.pago_monto = monto;
|
||||||
|
}
|
||||||
|
if (notas) payload.pago_notas = notas;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const r = await fetch('api/lab/registrar_pago.php', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(payload),
|
||||||
|
});
|
||||||
|
const res = await r.json();
|
||||||
|
if (!res.success) throw new Error(res.error || 'Error al guardar');
|
||||||
|
|
||||||
|
// Actualizar item en la agenda local para evitar recarga completa
|
||||||
|
const idx = (portal._agenda || []).findIndex(d => d.domicilio_id == domId);
|
||||||
|
if (idx >= 0) {
|
||||||
|
portal._agenda[idx].pago_estado = estado;
|
||||||
|
portal._agenda[idx].pago_modo = estado === 'pagado' ? modo : null;
|
||||||
|
portal._agenda[idx].pago_monto = estado === 'pagado' ? monto : null;
|
||||||
|
portal._agenda[idx].pago_notas = notas || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cerrar modal y re-renderizar
|
||||||
|
if (this._bsModal) this._bsModal.hide();
|
||||||
|
portal.renderAgenda();
|
||||||
|
} catch(e) {
|
||||||
|
alert('Error: ' + e.message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+42
-11
@@ -251,7 +251,16 @@ async function cargarLista(pag = 1) {
|
|||||||
<small class="text-muted">${esc(dom.barrio||'')}</small>
|
<small class="text-muted">${esc(dom.barrio||'')}</small>
|
||||||
</td>
|
</td>
|
||||||
<td>${dom.enfermera_nombre ? `<small>${esc(dom.enfermera_nombre)}</small>` : '<span class="text-danger small"><i class="fas fa-exclamation-triangle me-1"></i>Sin asignar</span>'}</td>
|
<td>${dom.enfermera_nombre ? `<small>${esc(dom.enfermera_nombre)}</small>` : '<span class="text-danger small"><i class="fas fa-exclamation-triangle me-1"></i>Sin asignar</span>'}</td>
|
||||||
<td><span class="badge bg-${COLOR_DOM[dom.estado]||'secondary'} estado-badge">${esc(dom.estado)}</span></td>
|
<td>
|
||||||
|
<span class="badge bg-${COLOR_DOM[dom.estado]||'secondary'} estado-badge">${esc(dom.estado)}</span>
|
||||||
|
${(dom.pago_estado === 'pagado')
|
||||||
|
? '<span class="badge rounded-pill ms-1" style="background:#d1fae5;color:#065f46;border:1px solid #34d399">✅ Pagado</span>'
|
||||||
|
: (dom.pago_estado === 'exento'
|
||||||
|
? '<span class="badge rounded-pill ms-1" style="background:#e0e7ff;color:#3730a3;border:1px solid #818cf8">🔵 Exento</span>'
|
||||||
|
: ((parseFloat(dom.valor_domicilio)||0)+(parseFloat(dom.valor_copago)||0) > 0
|
||||||
|
? '<span class="badge rounded-pill ms-1" style="background:#fff3cd;color:#664d03;border:1px solid #ffc107">⏳ Cobro</span>'
|
||||||
|
: ''))}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
`).join('');
|
`).join('');
|
||||||
|
|
||||||
@@ -371,17 +380,39 @@ async function verDomicilio(id) {
|
|||||||
<div class="bg-light p-2 rounded small">${esc(dom.examenes_solicitados||'—')}</div>
|
<div class="bg-light p-2 rounded small">${esc(dom.examenes_solicitados||'—')}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
${(dom.valor_domicilio || dom.valor_copago) ? `
|
${(dom.valor_domicilio || dom.valor_copago) ? (() => {
|
||||||
<div class="row mt-3">
|
const totalC = (parseFloat(dom.valor_domicilio)||0)+(parseFloat(dom.valor_copago)||0);
|
||||||
<div class="col-12">
|
const PAGO_INFO = {
|
||||||
<div class="d-flex gap-3 flex-wrap p-2 rounded" style="background:#d1fae5;border:1px solid #6ee7b7">
|
pendiente: { bg:'#fff3cd', color:'#664d03', border:'#ffc107', icon:'⏳', txt:'Pago pendiente' },
|
||||||
<span class="small fw-semibold text-success"><i class="fas fa-cash-register me-1"></i>Cobro al cliente:</span>
|
pagado: { bg:'#d1fae5', color:'#065f46', border:'#34d399', icon:'✅', txt:'Pagado' },
|
||||||
${dom.valor_domicilio ? `<span class="small">Domicilio: <strong>$${Number(dom.valor_domicilio).toLocaleString('es-CO')}</strong></span>` : ''}
|
exento: { bg:'#e0e7ff', color:'#3730a3', border:'#818cf8', icon:'🔵', txt:'Exento' },
|
||||||
${dom.valor_copago ? `<span class="small">Copago: <strong>$${Number(dom.valor_copago).toLocaleString('es-CO')}</strong></span>` : ''}
|
};
|
||||||
${ (dom.valor_domicilio && dom.valor_copago) ? `<span class="small fw-bold text-success">Total: $${(Number(dom.valor_domicilio)+Number(dom.valor_copago)).toLocaleString('es-CO')}</span>` : ''}
|
const pEst = dom.pago_estado || 'pendiente';
|
||||||
|
const pInfo = PAGO_INFO[pEst] || PAGO_INFO.pendiente;
|
||||||
|
const MODO_LABEL = { efectivo:'💵 Efectivo', transferencia:'📲 Transferencia', otro:'📋 Otro' };
|
||||||
|
return `
|
||||||
|
<div class="row mt-3">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="p-2 rounded" style="background:#d1fae5;border:1px solid #6ee7b7">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-1">
|
||||||
|
<span class="small fw-semibold text-success"><i class="fas fa-cash-register me-1"></i>Cobro al cliente</span>
|
||||||
|
<span class="badge rounded-pill small" style="background:${pInfo.bg};color:${pInfo.color};border:1px solid ${pInfo.border}">${pInfo.icon} ${pInfo.txt}</span>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex gap-3 flex-wrap">
|
||||||
|
${dom.valor_domicilio ? `<span class="small">Domicilio: <strong>$${Number(dom.valor_domicilio).toLocaleString('es-CO')}</strong></span>` : ''}
|
||||||
|
${dom.valor_copago ? `<span class="small">Copago: <strong>$${Number(dom.valor_copago).toLocaleString('es-CO')}</strong></span>` : ''}
|
||||||
|
${totalC > 0 ? `<span class="small fw-bold text-success">Total: $${totalC.toLocaleString('es-CO')}</span>` : ''}
|
||||||
|
</div>
|
||||||
|
${dom.pago_estado === 'pagado' ? `
|
||||||
|
<div class="small mt-1 text-success">
|
||||||
|
${MODO_LABEL[dom.pago_modo] || (dom.pago_modo||'')}
|
||||||
|
${dom.pago_monto ? ` · $${Number(dom.pago_monto).toLocaleString('es-CO')} cobrado` : ''}
|
||||||
|
${dom.pago_notas ? ` · <em>${esc(dom.pago_notas)}</em>` : ''}
|
||||||
|
</div>` : ''}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>`;
|
||||||
</div>` : ''}
|
})() : ''}
|
||||||
${dom.notas_admin ? `
|
${dom.notas_admin ? `
|
||||||
<div class="row mt-2">
|
<div class="row mt-2">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
|
|||||||
Reference in New Issue
Block a user