34849-vm/test_pedidos.php
2026-02-17 05:38:18 +00:00

441 lines
24 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
session_start();
if (!isset($_SESSION['user_id'])) {
header('Location: login.php');
exit;
}
require_once 'db/config.php';
function getStatusStyle($status) {
$style = 'color: white;'; // Default text color
$bgColor = '#0dcaf0'; // Default info blue
switch (strtoupper(trim($status))) {
case 'ROTULADO':
$bgColor = '#ffc107'; // yellow
$style = 'color: black;';
break;
case 'EN TRANSITO':
$bgColor = '#90EE90'; // light green
$style = 'color: black;';
break;
case 'EN DESTINO':
$bgColor = '#800080'; // purple
break;
case 'COMPLETADO':
case 'COMPLETADO ✅':
$bgColor = '#198754'; // dark green
break;
case 'GESTION':
$bgColor = '#6c757d'; // secondary grey
break;
}
return "background-color: {$bgColor} !important; {$style}";
}
$pdo = db();
$user_id = $_SESSION['user_id'];
$user_role = $_SESSION['user_role'] ?? 'Asesor';
// Fetch years for the filter
$years_query = "SELECT DISTINCT YEAR(created_at) as year FROM pedidos";
if ($user_role === 'Asesor') {
$years_query .= " WHERE asesor_id = ?";
$years_stmt = $pdo->prepare($years_query);
$years_stmt->execute([$user_id]);
} else {
$years_stmt = $pdo->query($years_query);
}
$years = $years_stmt->fetchAll(PDO::FETCH_COLUMN);
// Filter logic
$selected_month = $_GET['mes'] ?? '';
$selected_year = $_GET['año'] ?? '';
$search_query = $_GET['q'] ?? '';
$sql = "SELECT p.*, u.nombre_asesor as asesor_nombre FROM pedidos p LEFT JOIN users u ON p.asesor_id = u.id WHERE p.estado = 'EN TRANSITO 🚛'";
$params = [];
if ($user_role === 'Asesor') {
$sql .= " AND p.asesor_id = ?";
$params[] = $user_id;
}
if (!empty($search_query)) {
$sql .= " AND (p.nombre_completo LIKE ? OR p.dni_cliente LIKE ? OR p.celular LIKE ?)";
$params[] = "%$search_query%";
$params[] = "%$search_query%";
$params[] = "%$search_query%";
}
if (!empty($selected_month)) {
$sql .= " AND MONTH(p.created_at) = ?";
$params[] = $selected_month;
}
if (!empty($selected_year)) {
$sql .= " AND YEAR(p.created_at) = ?";
$params[] = $selected_year;
}
$sql .= " ORDER BY p.created_at DESC";
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$pedidos = $stmt->fetchAll();
$months = [
1 => 'Enero', 2 => 'Febrero', 3 => 'Marzo', 4 => 'Abril', 5 => 'Mayo', 6 => 'Junio',
7 => 'Julio', 8 => 'Agosto', 9 => 'Septiembre', 10 => 'Octubre', 11 => 'Noviembre', 12 => 'Diciembre'
];
?>
<?php
$pageTitle = "Pedidos en Tránsito (Prueba API Shalom)";
include 'layout_header.php';
?>
<!-- Modal for tracking status -->
<div class="modal fade" id="trackingModal" tabindex="-1" aria-labelledby="trackingModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="trackingModalLabel">Estado del Envío - Shalom</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p><strong>Nº De Orden:</strong> <span id="modal-order-number"></span></p>
<p><strong>Código De Orden:</strong> <span id="modal-order-code"></span></p>
<hr>
<div id="modal-tracking-status">
<p class="text-center">Consultando estado en Shalom...</p>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cerrar</button>
</div>
</div>
</div>
</div>
<?php if (isset($_SESSION['flash_message'])):
$flash = $_SESSION['flash_message'];
unset($_SESSION['flash_message']);
?>
<div class="alert alert-<?php echo htmlspecialchars($flash['type']); ?> alert-dismissible fade show" role="alert">
<?php echo htmlspecialchars($flash['message']); ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php endif; ?>
<div class="card mb-4">
<div class="card-body">
<form method="GET" action="test_pedidos.php" class="row g-3 align-items-center">
<div class="col-auto">
<label for="q" class="form-label">Buscar</label>
<input type="text" name="q" id="q" class="form-control" value="<?php echo htmlspecialchars($search_query); ?>" placeholder="Nombre, DNI o Celular">
</div>
<div class="col-auto">
<label for="mes" class="form-label">Mes</label>
<select name="mes" id="mes" class="form-select">
<option value="">Todos</option>
<?php foreach ($months as $num => $name): ?>
<option value="<?php echo $num; ?>" <?php echo $selected_month == $num ? 'selected' : ''; ?>><?php echo $name; ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-auto">
<label for="año" class="form-label">Año</label>
<select name="año" id="año" class="form-select">
<option value="">Todos</option>
<?php foreach ($years as $year): ?>
<option value="<?php echo $year; ?>" <?php echo $selected_year == $year ? 'selected' : ''; ?>><?php echo $year; ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-auto mt-4">
<button type="submit" class="btn btn-info">Filtrar</button>
<a href="test_pedidos.php" class="btn btn-secondary">Limpiar</a>
</div>
</form>
</div>
</div>
<div class="card">
<div class="card-body">
<div class="table-responsive">
<table id="pedidos-table" class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>Cliente</th>
<th>DNI</th>
<th>Celular</th>
<th>Producto</th>
<th>Sede de Envío</th>
<th>Cantidad</th>
<th>Monto Total</th>
<th>Monto Debe</th>
<th>Nº De Orden</th>
<th>Codigo De Orden</th>
<th>CLAVE</th>
<th>Estado</th>
<?php if ($user_role !== 'Asesor'): ?><th>Asesor</th><?php endif; ?>
<th>Fecha Creación</th>
<th>Voucher Restante</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
<?php foreach ($pedidos as $pedido): ?>
<tr>
<td><?php echo htmlspecialchars($pedido['id']); ?></td>
<td><?php echo htmlspecialchars($pedido['nombre_completo']); ?></td>
<td><?php echo htmlspecialchars($pedido['dni_cliente'] ?? 'N/A'); ?></td>
<td>
<?php
echo htmlspecialchars($pedido['celular']);
// Prepare WhatsApp message
$nombre_cliente = $pedido['nombre_completo'];
$producto = $pedido['producto'];
// The user template has {CIUDAD} / {AGENCIA}, we'll use sede_envio for both.
$sede_envio = $pedido['sede_envio'] ?? 'su agencia de destino';
$monto_total = (float)($pedido['monto_total'] ?? 0);
$monto_debe = (float)($pedido['monto_debe'] ?? 0);
$adelanto = $monto_total - $monto_debe;
$template = "PLANTILLA AVISO DE CLAVE DE RECOJO SHALOM\n\n"
. "Estimado(a) {NOMBRE_CLIENTE} 👋\n"
. "Le informamos que su pedido de {PRODUCTO} ya se encuentra disponible en su ciudad 📦\n\n"
. "📍 Lugar de recojo: Shalom {SEDE_ENVIO}\n\n"
. "💰 Detalle de pago:\n"
. "• Monto total del pedido: S/ {MONTO_TOTAL}\n"
. "• Adelanto realizado: S/ {ADELANTO} ✅\n"
. "• Saldo pendiente: S/ {SALDO_PENDIENTE}\n\n"
. "Para continuar, le solicitamos enviar la captura de su pago restante por este medio 📄\n\n"
. "Una vez confirmado su pago ✅, le enviaremos su clave de recojo 🔐, para que pueda retirar su pedido en la agencia sin inconvenientes 📦\n\n"
. "Quedamos atentos a su confirmación.\n"
. "Muchas gracias por su confianza 🤝\n\n"
. "Floower Store 🛍️\n"
. "Área de Atención al Cliente";
$replacements = [
'{NOMBRE_CLIENTE}' => $nombre_cliente,
'{PRODUCTO}' => $producto,
'{SEDE_ENVIO}' => $sede_envio,
'{MONTO_TOTAL}' => number_format($monto_total, 2),
'{ADELANTO}' => number_format($adelanto, 2),
'{SALDO_PENDIENTE}' => number_format($monto_debe, 2)
];
$whatsappMessage = str_replace(array_keys($replacements), array_values($replacements), $template);
$whatsappMessage = urlencode($whatsappMessage);
$celular = preg_replace('/[^0-9]/', '', $pedido['celular']);
if (strlen($celular) == 9) {
$celular = '51' . $celular;
}
$whatsappUrl = "https://api.whatsapp.com/send?phone={$celular}&text={$whatsappMessage}";
?>
<div class="mt-1">
<button type="button" class="btn btn-sm btn-info" title="Consultar Estado" data-bs-toggle="modal" data-bs-target="#trackingModal" data-order-number="<?php echo htmlspecialchars($pedido['codigo_rastreo'] ?? 'N/A'); ?>" data-order-code="<?php echo htmlspecialchars($pedido['codigo_tracking'] ?? 'N/A'); ?>">🔍</button>
<a href="<?php echo $whatsappUrl; ?>" target="_blank" class="btn btn-sm btn-success" title="Enviar WhatsApp">💬</a>
</div>
</td>
<td><?php echo htmlspecialchars($pedido['producto']); ?></td>
<td><?php echo htmlspecialchars($pedido['sede_envio'] ?? 'N/A'); ?></td>
<td><?php echo htmlspecialchars($pedido['cantidad'] ?: 1); ?></td>
<td><?php echo htmlspecialchars($pedido['monto_total']); ?></td>
<td><?php echo htmlspecialchars($pedido['monto_debe']); ?></td>
<td>
<button type="button" class="btn btn-link tracking-btn"
data-bs-toggle="modal"
data-bs-target="#trackingModal"
data-order-number="<?php echo htmlspecialchars($pedido['codigo_rastreo'] ?? 'N/A'); ?>"
data-order-code="<?php echo htmlspecialchars($pedido['codigo_tracking'] ?? 'N/A'); ?>">
<?php echo htmlspecialchars($pedido['codigo_rastreo'] ?? 'N/A'); ?>
</button>
</td>
<td class="editable" data-id="<?php echo $pedido['id']; ?>" data-field="codigo_tracking"><?php echo htmlspecialchars($pedido['codigo_tracking'] ?? 'N/A'); ?></td>
<td class="editable" data-id="<?php echo $pedido['id']; ?>" data-field="clave"><?php echo htmlspecialchars($pedido['clave'] ?? 'N/A'); ?></td>
<td><span class="badge" style="<?php echo getStatusStyle($pedido['estado']); ?>"><?php echo ($pedido['estado'] == 'Gestion') ? 'GESTIONES ⚙️' : htmlspecialchars($pedido['estado']); ?></span></td>
<?php if ($user_role !== 'Asesor'): ?><td><?php echo htmlspecialchars($pedido['asesor_nombre'] ?? 'N/A'); ?></td><?php endif; ?>
<td><?php echo htmlspecialchars($pedido['created_at']); ?></td>
<td>
<?php if (!empty($pedido['voucher_restante_path'])): ?>
<a href="<?php echo htmlspecialchars($pedido['voucher_restante_path']); ?>" target="_blank">Ver</a>
<?php else: ?>
N/A
<?php endif; ?>
</td>
<td>
<a href="pedido_form.php?id=<?php echo $pedido['id']; ?>" class="btn btn-sm btn-warning">Editar</a>
<?php if ($user_role === 'Administrador'): ?>
<a href="delete_pedido.php?id=<?php echo $pedido['id']; ?>" class="btn btn-sm btn-danger" onclick="return confirm('¿Estás seguro de que quieres eliminar este pedido?');">Eliminar</a>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php if (empty($pedidos)): ?>
<p class="text-center">No hay pedidos que coincidan con el filtro.</p>
<?php endif; ?>
</div>
</div>
</div>
<?php include 'layout_footer.php'; ?>
<script>
$(document).ready(function() {
$('#pedidos-table').DataTable({
"language": {
"url": "//cdn.datatables.net/plug-ins/1.10.25/i18n/Spanish.json"
},
"order": [[ <?php echo ($user_role !== 'Asesor' ? 13 : 12); ?>, "desc" ]],
"paging": false,
"lengthChange": false,
"info": false
});
});
document.addEventListener('DOMContentLoaded', function() {
const table = document.querySelector('.table');
// Logic for editable cells (existing logic)
table.addEventListener('click', function(e) {
if (e.target && e.target.classList.contains('editable')) {
// ... (la lógica de edición en línea se mantiene igual)
}
});
// Logic for tracking modal
var trackingModal = document.getElementById('trackingModal');
trackingModal.addEventListener('show.bs.modal', function (event) {
var button = event.relatedTarget;
var orderNumber = button.getAttribute('data-order-number');
var orderCode = button.getAttribute('data-order-code');
var modalOrderNumberSpan = trackingModal.querySelector('#modal-order-number');
var modalOrderCodeSpan = trackingModal.querySelector('#modal-order-code');
var modalStatusDiv = trackingModal.querySelector('#modal-tracking-status');
// 1. Populate the modal with initial info
modalOrderNumberSpan.textContent = orderNumber;
modalOrderCodeSpan.textContent = orderCode;
modalStatusDiv.innerHTML = '<p class="text-center">Consultando estado en Shalom...</p>';
// 2. Check if we have valid codes
if (orderNumber === 'N/A' || orderCode === 'N/A' || !orderNumber || !orderCode) {
modalStatusDiv.innerHTML = '<p class="text-danger text-center">No hay suficientes datos (Nº de Orden o Código de Orden) para consultar.</p>';
return;
}
// 3. Fetch the tracking status from our new API endpoint
fetch(`shalom_api.php?orderNumber=${encodeURIComponent(orderNumber)}&orderCode=${encodeURIComponent(orderCode)}`)
.then(response => {
if (!response.ok) {
// Try to get error message from Shalom API response body
return response.json().then(errorData => {
throw new Error(errorData.error || `Error del servidor: ${response.status}`);
});
}
return response.json();
})
.then(data => {
// 4. Display the result
if (data.error) {
modalStatusDiv.innerHTML = `<p class="text-danger text-center"><strong>Error:</strong> ${data.error}</p>`;
} else if (data.search && data.search.success) {
const searchData = data.search.data;
const statusData = data.statuses.data;
const statusMessage = data.statuses.message || 'No disponible';
let html = `
<div class="alert alert-info text-center">
<h5 class="alert-heading mb-0">Estado: ${statusMessage}</h5>
</div>
<div class="row">
<div class="col-md-6">
<div class="card mb-3">
<div class="card-header"><strong>Origen</strong></div>
<div class="card-body">
<p class="card-text mb-1">${searchData.origen.nombre}</p>
<p class="card-text mb-0"><small class="text-muted">${searchData.origen.direccion}</small></p>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card mb-3">
<div class="card-header"><strong>Destino</strong></div>
<div class="card-body">
<p class="card-text mb-1">${searchData.destino.nombre}</p>
<p class="card-text mb-0"><small class="text-muted">${searchData.destino.direccion}</small></p>
</div>
</div>
</div>
</div>
<div class="card mb-3">
<div class="card-header"><strong>Detalles del Envío</strong></div>
<ul class="list-group list-group-flush">
<li class="list-group-item"><strong>Remitente:</strong> ${searchData.remitente.nombre}</li>
<li class="list-group-item"><strong>Destinatario:</strong> ${searchData.destinatario.nombre}</li>
<li class="list-group-item"><strong>Fecha de Emisión:</strong> ${new Date(searchData.fecha_emision).toLocaleString('es-PE', { timeZone: 'America/Lima' })}</li>
<li class="list-group-item"><strong>Contenido:</strong> ${searchData.contenido}</li>
<li class="list-group-item"><strong>Monto a Pagar:</strong> S/ ${parseFloat(searchData.monto).toFixed(2)} (${searchData.tipo_pago})</li>
</ul>
</div>
<div class="card">
<div class="card-header"><strong>Historial de Estados</strong></div>
<div class="card-body" style="font-size: 0.9rem;">
`;
const timeline = [
{ name: 'Registrado', data: statusData.registrado },
{ name: 'En Origen', data: statusData.origen },
{ name: 'En Tránsito', data: statusData.transito },
{ name: 'En Destino', data: statusData.destino },
{ name: 'En Reparto', data: statusData.reparto },
{ name: 'Entregado', data: statusData.entregado }
];
timeline.forEach(item => {
if (item.data && item.data.fecha) {
html += `<p class="mb-1"><strong>${item.name}:</strong> <span class="text-success">${new Date(item.data.fecha).toLocaleString('es-PE', { timeZone: 'America/Lima' })}</span></p>`;
} else {
html += `<p class="mb-1"><strong>${item.name}:</strong> <span class="text-muted">Pendiente</span></p>`;
}
});
html += `
</div>
</div>
`;
modalStatusDiv.innerHTML = html;
} else {
modalStatusDiv.innerHTML = `<p class="text-warning text-center">No se pudo encontrar la guía o la respuesta no es válida.</p><pre><code>${JSON.stringify(data, null, 2)}</code></pre>`;
}
})
.catch(error => {
// 5. Handle fetch or other errors
console.error('Error fetching tracking status:', error);
modalStatusDiv.innerHTML = `<p class="text-danger text-center"><strong>Error al consultar:</strong> ${error.message}</p>`;
});
});
});
</script>