antes del cambio de color de los botones
This commit is contained in:
parent
d0430dd891
commit
e113c750b9
11
CHANGELOG.md
11
CHANGELOG.md
@ -1,5 +1,16 @@
|
|||||||
# CHANGELOG - SIIP WhatsApp Notifications Plugin
|
# CHANGELOG - SIIP WhatsApp Notifications Plugin
|
||||||
|
|
||||||
|
## VERSIÓN 4.4.0 - 10-03-2026
|
||||||
|
|
||||||
|
### ✨ Nuevas Características (Features)
|
||||||
|
|
||||||
|
1️⃣ **Reenvío manual de notificaciones de tareas**: Nuevo módulo en la sección "Gestión de Instaladores" que permite ver las tareas activas ("En curso") de cada técnico y reenviar manualmente la notificación WhatsApp de asignación con un solo clic.
|
||||||
|
|
||||||
|
- **Nuevo endpoint `GET ?action=get_installer_jobs`**: Consulta la API de UCRM para obtener los jobs activos (`status=1`) filtrados por instalador, enriquecidos con nombre del cliente.
|
||||||
|
- **Nuevo endpoint `POST action=resend_job_notification`**: Simula un webhook `job.edit` (status 0→1) vía loopback curl para disparar el flujo completo de notificación.
|
||||||
|
- **Tabla interactiva**: Card "📋 Tareas Activas del Instalador" con columnas Folio, Cliente, Fecha, Descripción y botón 📨 Reenviar.
|
||||||
|
- **Icono 📋 en tabla de instaladores**: Permite cargar las tareas activas de cualquier técnico con un clic.
|
||||||
|
|
||||||
## VERSIÓN 4.3.1 - 10-03-2026
|
## VERSIÓN 4.3.1 - 10-03-2026
|
||||||
|
|
||||||
### 🐛 Correcciones (Bug Fixes)
|
### 🐛 Correcciones (Bug Fixes)
|
||||||
|
|||||||
@ -1,12 +1,18 @@
|
|||||||
# SIIP - WhatsApp Notifications & Integrated Payment Portal
|
# SIIP - WhatsApp Notifications & Integrated Payment Portal
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
Este plugin es una solución integral que transforma tu UCRM en un **Portal Administrativo de Última Generación**. No solo automatiza la comunicación por WhatsApp, sino que integra un Dashboard completo para la gestión de pagos online (Stripe/OXXO), visualización de comprobantes y coordinación de equipos técnicos.
|
Este plugin es una solución integral que transforma tu UCRM en un **Portal Administrativo de Última Generación**. No solo automatiza la comunicación por WhatsApp, sino que integra un Dashboard completo para la gestión de pagos online (Stripe/OXXO), visualización de comprobantes y coordinación de equipos técnicos.
|
||||||
|
|
||||||
|
## ✨ Novedades v4.4.0 (Resend Job Notifications)
|
||||||
|
|
||||||
|
- **📋 Tabla de Tareas Activas por Instalador**: Nuevo módulo dentro de "Gestión de Instaladores" que muestra los jobs "En curso" de cada técnico con datos de cliente, fecha y descripción.
|
||||||
|
- **📨 Reenvío Manual de Notificaciones**: Botón para reenviar la notificación WhatsApp de asignación de tarea a cualquier instalador desde la interfaz del plugin.
|
||||||
|
- **🔗 Integración con API de Scheduling**: Consulta dinámica de `GET /scheduling/jobs?assignedUserId=X&statuses[]=1` para listar tareas activas en tiempo real.
|
||||||
|
|
||||||
## 🐛 Hotfix v4.3.1 (Installer Notification Fix)
|
## 🐛 Hotfix v4.3.1 (Installer Notification Fix)
|
||||||
|
|
||||||
- **🔧 Fix Cambio de Instalador**: Corregido bug donde el nuevo técnico recibía mensaje de desasignación en vez de asignación al cambiar instalador en una tarea "En curso".
|
- **🔧 Fix Cambio de Instalador**: Corregido bug donde el nuevo técnico recibía mensaje de desasignación en vez de asignación al cambiar instalador en una tarea "En curso".
|
||||||
|
|||||||
@ -1 +1,35 @@
|
|||||||
{"ipserver":"venus.siip.mx","apitoken":"gvcnIJqXdUjneVSjhl6THLlQcYXJyIFCcwHKVba2bvIrNraanCTb5VeoWuJ0TFZ9","unmsApiToken":"4f5219de-cc5b-413d-b2fb-5133d02f3b26","tokencallbell":"g8thcZkXGd3xBj2g3TtYNYFMH1fuesbJ.b6a940ea7d78cf6c9e42f067b21c8ddf96e9fa2a9e307bfd0c7c7c4d7fa38f79","tokenstripe":"sk_test_51OkG0REFY1WEUtgRH6UxBK5pu80Aq5Iy8EcdPnf0cOWzuVLQTpyLCd7CbPzqMsWMafZOHElCxhEHF7g8boURjWlJ00tBwE0W1M","hostServerFTP":"siip.mx","usernameServerFTP":"siip0001","passServerFTP":"$spGiT,[wa)n","ipPuppeteer":"172.16.5.134","portPuppeteer":"4100","idPaymentAdminCRM":"1180","cashPaymentMethodId":true,"courtesyPaymentMethodId":true,"bankTransferPaymentMethodId":true,"paypalPaymentMethodId":true,"creditCardPaypalPaymentMethodId":true,"creditCardStripePaymentMethodId":true,"stripeSubscriptionCreditCardPaymentMethodId":true,"paypalSubscriptionPaymentMethodId":true,"mercadopagoPaymentMethodId":true,"checkPaymentMethodId":true,"customPaymentMethodId":true,"oxxoPayPaymentMethodId":true,"creditDebitCardPaymentMethodId":true,"notificationTypeText":false,"installersDataWhatsApp":"{\"instaladores\":[{\"id\":1019,\"nombre\":\"Mucio Robledo\",\"whatsapp\":\"4181878106\"},{\"id\":1173,\"nombre\":\"Ángel Arvizu\",\"whatsapp\":\"4181878106\"},{\"id\":1172,\"nombre\":\"Juan Rostro\",\"whatsapp\":\"4181878106\"},{\"id\":1015,\"nombre\":\"Daniel Humberto\",\"whatsapp\":\"4181878106\"},{\"id\":1131,\"nombre\":\"Gricelda Avalos\",\"whatsapp\":\"4181817609\"}]}","debugMode":true,"minioEndpoint":"http://172.16.5.134:9002","minioPublicUrl":"https://aws-venus.siip.mx","minioAccessKey":"minioadmin","minioSecretKey":"minioadmin","minioBucket":"vouchers-oxxo","logging_level":true}
|
{
|
||||||
|
"ipserver": "venus.siip.mx",
|
||||||
|
"apitoken": "gvcnIJqXdUjneVSjhl6THLlQcYXJyIFCcwHKVba2bvIrNraanCTb5VeoWuJ0TFZ9",
|
||||||
|
"unmsApiToken": "4f5219de-cc5b-413d-b2fb-5133d02f3b26",
|
||||||
|
"tokencallbell": "g8thcZkXGd3xBj2g3TtYNYFMH1fuesbJ.b6a940ea7d78cf6c9e42f067b21c8ddf96e9fa2a9e307bfd0c7c7c4d7fa38f79",
|
||||||
|
"tokenstripe": "sk_test_51OkG0REFY1WEUtgRH6UxBK5pu80Aq5Iy8EcdPnf0cOWzuVLQTpyLCd7CbPzqMsWMafZOHElCxhEHF7g8boURjWlJ00tBwE0W1M",
|
||||||
|
"hostServerFTP": "siip.mx",
|
||||||
|
"usernameServerFTP": "siip0001",
|
||||||
|
"passServerFTP": "$spGiT,[wa)n",
|
||||||
|
"ipPuppeteer": "172.16.5.134",
|
||||||
|
"portPuppeteer": "4100",
|
||||||
|
"idPaymentAdminCRM": "1180",
|
||||||
|
"cashPaymentMethodId": true,
|
||||||
|
"courtesyPaymentMethodId": true,
|
||||||
|
"bankTransferPaymentMethodId": true,
|
||||||
|
"paypalPaymentMethodId": true,
|
||||||
|
"creditCardPaypalPaymentMethodId": true,
|
||||||
|
"creditCardStripePaymentMethodId": true,
|
||||||
|
"stripeSubscriptionCreditCardPaymentMethodId": true,
|
||||||
|
"paypalSubscriptionPaymentMethodId": true,
|
||||||
|
"mercadopagoPaymentMethodId": true,
|
||||||
|
"checkPaymentMethodId": true,
|
||||||
|
"customPaymentMethodId": true,
|
||||||
|
"oxxoPayPaymentMethodId": true,
|
||||||
|
"creditDebitCardPaymentMethodId": true,
|
||||||
|
"notificationTypeText": false,
|
||||||
|
"installersDataWhatsApp": "{\"instaladores\":[{\"id\":1019,\"nombre\":\"Mucio Robledo\",\"whatsapp\":\"4181878106\"},{\"id\":1173,\"nombre\":\"Ángel Arvizu\",\"whatsapp\":\"4181878106\"},{\"id\":1172,\"nombre\":\"Juan Rostro\",\"whatsapp\":\"4181878106\"},{\"id\":1015,\"nombre\":\"Daniel Humberto\",\"whatsapp\":\"4181878106\"},{\"id\":1131,\"nombre\":\"Gricelda Avalos\",\"whatsapp\":\"4181817609\"},{\"id\":\"1184\",\"nombre\":\"José Luis Enrique Sánchez\",\"whatsapp\":\"4181878106\"}]}",
|
||||||
|
"debugMode": true,
|
||||||
|
"minioEndpoint": "http:\/\/172.16.5.134:9002",
|
||||||
|
"minioPublicUrl": "https:\/\/aws-venus.siip.mx",
|
||||||
|
"minioAccessKey": "minioadmin",
|
||||||
|
"minioSecretKey": "minioadmin",
|
||||||
|
"minioBucket": "vouchers-oxxo",
|
||||||
|
"logging_level": true
|
||||||
|
}
|
||||||
16138
data/plugin.log
16138
data/plugin.log
File diff suppressed because one or more lines are too long
@ -5,13 +5,18 @@
|
|||||||
"displayName": "SIIP - Procesador de Pagos en línea con Stripe, Oxxo y Transferencia, Sincronizador de CallBell y Envío de Notificaciones y comprobantes vía WhatsApp",
|
"displayName": "SIIP - Procesador de Pagos en línea con Stripe, Oxxo y Transferencia, Sincronizador de CallBell y Envío de Notificaciones y comprobantes vía WhatsApp",
|
||||||
"description": "Este plugin sincroniza los clientes del sistema UISP CRM con los contactos de WhatsApp en CallBell, además procesa pagos de Stripe como las trasferencias bancarias y genera referencias de pago vía OXXO, además envía comprobantes de pago en formato imagen PNG o texto vía Whatsapp a los clientes",
|
"description": "Este plugin sincroniza los clientes del sistema UISP CRM con los contactos de WhatsApp en CallBell, además procesa pagos de Stripe como las trasferencias bancarias y genera referencias de pago vía OXXO, además envía comprobantes de pago en formato imagen PNG o texto vía Whatsapp a los clientes",
|
||||||
"url": "https://siip.mx/",
|
"url": "https://siip.mx/",
|
||||||
"version": "4.3.1",
|
"version": "4.4.0",
|
||||||
"unmsVersionCompliancy": {
|
"unmsVersionCompliancy": {
|
||||||
"min": "2.1.0",
|
"min": "2.1.0",
|
||||||
"max": null
|
"max": null
|
||||||
},
|
},
|
||||||
"author": "SIIP INTERNET",
|
"author": "SIIP INTERNET",
|
||||||
"changelog": [
|
"changelog": [
|
||||||
|
{
|
||||||
|
"version": "4.4.0",
|
||||||
|
"date": "2026-03-10",
|
||||||
|
"changes": "Nueva funcionalidad: Reenvío manual de notificaciones de tareas a instaladores desde el módulo Gestión de Instaladores. Tabla de jobs activos por técnico con botón de reenvío."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "4.3.1",
|
"version": "4.3.1",
|
||||||
"date": "2026-03-10",
|
"date": "2026-03-10",
|
||||||
|
|||||||
232
public.php
232
public.php
@ -236,6 +236,60 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|||||||
}
|
}
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($_POST['action'] === 'resend_job_notification') {
|
||||||
|
$jobId = $_POST['jobId'] ?? null;
|
||||||
|
if (!$jobId) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'jobId requerido']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$job = $ucrmApi->get("scheduling/jobs/$jobId");
|
||||||
|
$client = $ucrmApi->get("clients/{$job['clientId']}");
|
||||||
|
|
||||||
|
// Simular webhook job.edit con activación (status 0→1)
|
||||||
|
$entityBeforeEdit = $job;
|
||||||
|
$entityBeforeEdit['status'] = 0; // Simular que estaba en "Abierto"
|
||||||
|
$entity = $job;
|
||||||
|
$entity['status'] = 1; // Estado actual: "En curso"
|
||||||
|
// Agregar prefijo para que verifyJobActionToDo reconozca que debe notificar
|
||||||
|
$entity['title'] = '[NOTIFICACION-PENDIENTE]' . ($entity['title'] ?? '');
|
||||||
|
|
||||||
|
$payload = [
|
||||||
|
'uuid' => 'manual-trigger',
|
||||||
|
'changeType' => 'update',
|
||||||
|
'entity' => 'job',
|
||||||
|
'entityId' => (int)$jobId,
|
||||||
|
'eventName' => 'job.edit',
|
||||||
|
'extraData' => [
|
||||||
|
'entity' => $entity,
|
||||||
|
'entityBeforeEdit' => $entityBeforeEdit
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
|
||||||
|
$selfUrl = $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
|
||||||
|
|
||||||
|
$ch = curl_init($selfUrl);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||||
|
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||||
|
curl_setopt($ch, CURLOPT_POSTREDIR, 3);
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||||
|
$res = curl_exec($ch);
|
||||||
|
$err = curl_error($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
echo json_encode(['success' => true, 'message' => 'Notificación reenviada para job #' . $jobId]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_GET['action'])) {
|
if (isset($_GET['action'])) {
|
||||||
@ -268,6 +322,45 @@ if (isset($_GET['action'])) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($_GET['action'] === 'get_installer_jobs') {
|
||||||
|
$installerId = $_GET['installerId'] ?? null;
|
||||||
|
if (!$installerId) {
|
||||||
|
echo json_encode([]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$jobs = $ucrmApi->get('scheduling/jobs', [
|
||||||
|
'assignedUserId' => $installerId,
|
||||||
|
'statuses[]' => 1,
|
||||||
|
'limit' => 50
|
||||||
|
]);
|
||||||
|
$result = [];
|
||||||
|
foreach ($jobs as $job) {
|
||||||
|
$clientName = 'Sin cliente';
|
||||||
|
if (!empty($job['clientId'])) {
|
||||||
|
try {
|
||||||
|
$client = $ucrmApi->get("clients/{$job['clientId']}");
|
||||||
|
$clientName = trim(($client['firstName'] ?? '') . ' ' . ($client['lastName'] ?? ''));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$clientName = 'Cliente #' . $job['clientId'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$result[] = [
|
||||||
|
'id' => $job['id'],
|
||||||
|
'title' => $job['title'] ?? 'Sin título',
|
||||||
|
'date' => $job['date'] ?? '',
|
||||||
|
'clientName' => $clientName,
|
||||||
|
'clientId' => $job['clientId'] ?? null,
|
||||||
|
'description' => mb_substr($job['description'] ?? '', 0, 80)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
echo json_encode($result);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
echo json_encode([]);
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
if ($_GET['action'] === 'image' || $_GET['action'] === 'get_image') {
|
if ($_GET['action'] === 'image' || $_GET['action'] === 'get_image') {
|
||||||
// Image Handler
|
// Image Handler
|
||||||
if (ob_get_level()) ob_end_clean();
|
if (ob_get_level()) ob_end_clean();
|
||||||
@ -1717,6 +1810,46 @@ $installersData = json_decode($config['installersDataWhatsApp'] ?? '{"instalador
|
|||||||
<p>No se encontraron instaladores</p>
|
<p>No se encontraron instaladores</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- JOBS ACTIVOS DEL INSTALADOR -->
|
||||||
|
<div class="card" style="margin-top: 2rem;">
|
||||||
|
<div style="margin-bottom: 1.5rem;">
|
||||||
|
<h2 id="jobsSectionTitle" style="margin: 0; display: flex; align-items: center; gap: 10px;">
|
||||||
|
📋 Tareas Activas del Instalador
|
||||||
|
</h2>
|
||||||
|
<p style="color: var(--text-muted); margin: 5px 0 0 0;">Selecciona un instalador con el botón 📋 para ver sus tareas "En curso" y reenviar notificaciones</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="jobsEmptyState" class="placeholder-state">
|
||||||
|
<span class="placeholder-icon">👷</span>
|
||||||
|
<p>Selecciona un instalador para ver sus tareas activas</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="jobsLoading" style="display: none; text-align: center; padding: 2rem; color: var(--text-muted);">
|
||||||
|
<div class="loader" style="margin: 0 auto 1rem;"></div>
|
||||||
|
<p>Cargando tareas...</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="jobsTableWrapper" style="display: none; overflow-x: auto;">
|
||||||
|
<table id="installerJobsTable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Folio</th>
|
||||||
|
<th>Cliente</th>
|
||||||
|
<th>Fecha</th>
|
||||||
|
<th>Descripción</th>
|
||||||
|
<th>Acción</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="jobsNoResults" class="placeholder-state" style="display: none;">
|
||||||
|
<span class="placeholder-icon">✅</span>
|
||||||
|
<p>Este instalador no tiene tareas "En curso"</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- MODULE 2: NOTIFICATIONS -->
|
<!-- MODULE 2: NOTIFICATIONS -->
|
||||||
@ -2659,6 +2792,7 @@ $installersData = json_decode($config['installersDataWhatsApp'] ?? '{"instalador
|
|||||||
<td>${inst.nombre}</td>
|
<td>${inst.nombre}</td>
|
||||||
<td>${inst.whatsapp}</td>
|
<td>${inst.whatsapp}</td>
|
||||||
<td>
|
<td>
|
||||||
|
<span style="cursor:pointer; font-size:1.3em; margin-right:8px;" onclick="loadInstallerJobs('${inst.id}', '${inst.nombre}')" title="Ver tareas activas">📋</span>
|
||||||
<img src="?action=image&file=edit.webp" class="icon-action" onclick="editInstaller(${i})" title="Editar">
|
<img src="?action=image&file=edit.webp" class="icon-action" onclick="editInstaller(${i})" title="Editar">
|
||||||
<img src="?action=image&file=delete.webp" class="icon-action" style="margin-left:10px" onclick="deleteInstaller(${i})" title="Borrar">
|
<img src="?action=image&file=delete.webp" class="icon-action" style="margin-left:10px" onclick="deleteInstaller(${i})" title="Borrar">
|
||||||
</td>
|
</td>
|
||||||
@ -2703,6 +2837,104 @@ $installersData = json_decode($config['installersDataWhatsApp'] ?? '{"instalador
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- JOBS ACTIVOS DEL INSTALADOR ---
|
||||||
|
async function loadInstallerJobs(installerId, installerName) {
|
||||||
|
const title = document.getElementById('jobsSectionTitle');
|
||||||
|
const emptyState = document.getElementById('jobsEmptyState');
|
||||||
|
const loading = document.getElementById('jobsLoading');
|
||||||
|
const tableWrapper = document.getElementById('jobsTableWrapper');
|
||||||
|
const noResults = document.getElementById('jobsNoResults');
|
||||||
|
|
||||||
|
title.innerHTML = `📋 Tareas Activas: <strong>${installerName}</strong>`;
|
||||||
|
emptyState.style.display = 'none';
|
||||||
|
loading.style.display = 'block';
|
||||||
|
tableWrapper.style.display = 'none';
|
||||||
|
noResults.style.display = 'none';
|
||||||
|
|
||||||
|
// Scroll suave a la sección de jobs
|
||||||
|
title.scrollIntoView({
|
||||||
|
behavior: 'smooth',
|
||||||
|
block: 'start'
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const resp = await fetch(`?action=get_installer_jobs&installerId=${installerId}`);
|
||||||
|
const jobs = await resp.json();
|
||||||
|
loading.style.display = 'none';
|
||||||
|
|
||||||
|
if (!jobs.length) {
|
||||||
|
noResults.style.display = 'block';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tbody = document.querySelector('#installerJobsTable tbody');
|
||||||
|
tbody.innerHTML = jobs.map(job => {
|
||||||
|
const dateFormatted = job.date ? new Date(job.date).toLocaleDateString('es-MX', {
|
||||||
|
day: '2-digit',
|
||||||
|
month: '2-digit',
|
||||||
|
year: 'numeric'
|
||||||
|
}) : 'S/F';
|
||||||
|
const titleClean = job.title.replace('[NOTIFICACION-PENDIENTE]', '').replace('[CLIENTE-SIN-WHATSAPP]', '').trim();
|
||||||
|
return `<tr>
|
||||||
|
<td><strong>#${job.id}</strong></td>
|
||||||
|
<td>[${job.clientId}] ${job.clientName}</td>
|
||||||
|
<td>${dateFormatted}</td>
|
||||||
|
<td style="max-width:200px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;" title="${job.description}">${titleClean || job.description || 'Sin descripción'}</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-primary" style="padding:6px 14px; font-size:0.85em;" onclick="resendJobNotification(${job.id}, this)">
|
||||||
|
📨 Reenviar
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>`;
|
||||||
|
}).join('');
|
||||||
|
tableWrapper.style.display = 'block';
|
||||||
|
} catch (e) {
|
||||||
|
loading.style.display = 'none';
|
||||||
|
noResults.style.display = 'block';
|
||||||
|
console.error('Error loading installer jobs:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resendJobNotification(jobId, btn) {
|
||||||
|
const originalText = btn.innerHTML;
|
||||||
|
btn.innerHTML = '⏳ Enviando...';
|
||||||
|
btn.disabled = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const fd = new FormData();
|
||||||
|
fd.append('action', 'resend_job_notification');
|
||||||
|
fd.append('jobId', jobId);
|
||||||
|
|
||||||
|
const resp = await fetch('', {
|
||||||
|
method: 'POST',
|
||||||
|
body: fd
|
||||||
|
});
|
||||||
|
const result = await resp.json();
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
btn.innerHTML = '✅ Enviado';
|
||||||
|
btn.style.backgroundColor = '#22c55e';
|
||||||
|
showToast('Notificación reenviada para tarea #' + jobId);
|
||||||
|
setTimeout(() => {
|
||||||
|
btn.innerHTML = originalText;
|
||||||
|
btn.style.backgroundColor = '';
|
||||||
|
btn.disabled = false;
|
||||||
|
}, 3000);
|
||||||
|
} else {
|
||||||
|
throw new Error(result.message || 'Error desconocido');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
btn.innerHTML = '❌ Error';
|
||||||
|
btn.style.backgroundColor = '#ef4444';
|
||||||
|
showToast('Error: ' + e.message, true);
|
||||||
|
setTimeout(() => {
|
||||||
|
btn.innerHTML = originalText;
|
||||||
|
btn.style.backgroundColor = '';
|
||||||
|
btn.disabled = false;
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function openInstallerModal() {
|
function openInstallerModal() {
|
||||||
document.getElementById('modalOverlay').style.display = 'flex';
|
document.getElementById('modalOverlay').style.display = 'flex';
|
||||||
document.getElementById('installerForm').reset();
|
document.getElementById('installerForm').reset();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user