diff --git a/admin/DashboardController.php b/admin/DashboardController.php index f0f4e49..911cb0c 100644 --- a/admin/DashboardController.php +++ b/admin/DashboardController.php @@ -1045,10 +1045,17 @@ HTML; $phonesHtml = << - Tipo 1 (Solo reporta): {$countT1} / {$limitType1} - Tipo 2+3 (Reciben): {$countT23} / {$limitType23} +
+
+ Tipo 1 (Solo reporta): {$countT1} / {$limitType1} + Tipo 2+3 (Reciben): {$countT23} / {$limitType23} +
+
+
@@ -1056,7 +1063,7 @@ HTML;
Número WAEtiquetaPermisoEstado
-
Agregar número
+
Agregar número manualmente
@@ -1222,6 +1229,29 @@ function showTab(name) { const initTab = new URLSearchParams(location.search).get('tab') || 'general'; showTab(initTab); +async function syncPhones(cid) { + const btn = document.getElementById('syncBtn'); + const msg = document.getElementById('syncMsg'); + btn.disabled = true; + btn.innerHTML = ' Sincronizando...'; + msg.innerHTML = ''; + const fd = new FormData(); fd.append('company_id', cid); + try { + const r = await fetch('/admin/company/phones/sync', {method:'POST', body:fd}); + const j = await r.json(); + if (j.ok) { + msg.innerHTML = '
' + j.message + '
'; + setTimeout(() => location.reload(), 1200); + } else { + msg.innerHTML = '
' + j.error + (j.detail ? '
' + j.detail + '' : '') + '
'; + } + } catch(e) { + msg.innerHTML = '
Error de red: ' + e.message + '
'; + } + btn.disabled = false; + btn.innerHTML = ' Sincronizar desde ERP'; +} + async function addPhone(cid) { const num = document.getElementById('newPhone').value.trim().replace(/\D/g,''); const lbl = document.getElementById('newPhoneLabel').value.trim(); @@ -1290,6 +1320,111 @@ HTML; echo Layout::close(); } + // ─── POST /admin/company/phones/sync ───────────────────────────────────── + + public static function companyPhonesSync(): void + { + SessionAuth::require(); + header('Content-Type: application/json; charset=utf-8'); + + $companyId = (int)($_POST['company_id'] ?? 0); + if ($companyId <= 0) { + echo json_encode(['ok' => false, 'error' => 'ID de empresa inválido']); + exit; + } + + $company = CompanyRepository::findById($companyId); + if (!$company) { + echo json_encode(['ok' => false, 'error' => 'Empresa no encontrada']); + exit; + } + + // Buscar endpoint numeros_dn configurado para esta empresa + $epRow = db()->prepare("SELECT url, method FROM company_endpoints WHERE company_id=? AND endpoint_key='numeros_dn' LIMIT 1"); + $epRow->execute([$companyId]); + $ep = $epRow->fetch(\PDO::FETCH_ASSOC); + + if (!$ep || empty($ep['url'])) { + echo json_encode(['ok' => false, 'error' => 'El endpoint "Informe de números activos" no está configurado en la pestaña Endpoints API.']); + exit; + } + + // Llamar al endpoint + $apiKey = $company['api_key'] ?? ''; + $ch = curl_init($ep['url']); + $opts = [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_TIMEOUT => 15, + CURLOPT_SSL_VERIFYPEER => false, + CURLOPT_HTTPHEADER => ['Accept: application/json'], + ]; + if ($apiKey !== '') $opts[CURLOPT_HTTPHEADER][] = 'Authorization: Bearer ' . $apiKey; + if (strtoupper($ep['method'] ?? 'GET') === 'POST') { + $opts[CURLOPT_POST] = true; + $opts[CURLOPT_POSTFIELDS] = '{}'; + $opts[CURLOPT_HTTPHEADER][] = 'Content-Type: application/json'; + } + curl_setopt_array($ch, $opts); + $resp = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $curlErr = curl_error($ch); + curl_close($ch); + + if ($curlErr) { + echo json_encode(['ok' => false, 'error' => 'No se pudo conectar al ERP.', 'detail' => $curlErr]); + exit; + } + if ($httpCode !== 200) { + echo json_encode(['ok' => false, 'error' => "El ERP respondió HTTP {$httpCode}.", 'detail' => substr((string)$resp, 0, 300)]); + exit; + } + + $data = json_decode($resp, true); + if (!is_array($data)) { + echo json_encode(['ok' => false, 'error' => 'La respuesta del ERP no es JSON válido.', 'detail' => substr((string)$resp, 0, 300)]); + exit; + } + + // Aceptar root array o {numeros:[...]} + $numeros = isset($data['numeros']) ? $data['numeros'] : (array_values($data) && is_array($data[0] ?? null) ? $data : []); + if (empty($numeros)) { + echo json_encode(['ok' => false, 'error' => 'El JSON no contiene números. Espera un array en "numeros" o un array raíz.', 'detail' => substr($resp, 0, 300)]); + exit; + } + + $inserted = 0; $updated = 0; $skipped = 0; + $pTypeMap = ['1' => 1, '2' => 2, '3' => 3, 1 => 1, 2 => 2, 3 => 3]; + + $stmt = db()->prepare(" + INSERT INTO company_phones (company_id, wa_number, label, permission_type) + VALUES (?, ?, ?, ?) + ON DUPLICATE KEY UPDATE label=VALUES(label), permission_type=VALUES(permission_type), is_active=1 + "); + + foreach ($numeros as $n) { + $waNumber = preg_replace('/\D/', '', (string)($n['wa_number'] ?? $n['numero'] ?? $n['phone'] ?? '')); + if (strlen($waNumber) < 7) { $skipped++; continue; } + + $label = trim((string)($n['nombre'] ?? $n['name'] ?? $n['label'] ?? '')); + $permRaw = $n['permiso'] ?? $n['permission_type'] ?? $n['tipo'] ?? 3; + $permission = $pTypeMap[(int)$permRaw] ?? 3; + + try { + $before = db()->prepare("SELECT id FROM company_phones WHERE company_id=? AND wa_number=?"); + $before->execute([$companyId, $waNumber]); + $exists = $before->fetch(); + $stmt->execute([$companyId, $waNumber, $label, $permission]); + $exists ? $updated++ : $inserted++; + } catch (\PDOException $e) { $skipped++; } + } + + echo json_encode([ + 'ok' => true, + 'message' => "Sincronización completa: {$inserted} nuevos, {$updated} actualizados, {$skipped} omitidos.", + ]); + exit; + } + // ─── POST /admin/company/phone/save ────────────────────────────────────── public static function companyPhoneSave(): void diff --git a/public/index.php b/public/index.php index cd6137d..f330e6b 100644 --- a/public/index.php +++ b/public/index.php @@ -268,6 +268,7 @@ $routes = [ // ─── Números WhatsApp por empresa ────────────────────────────────────── ['POST', '/admin/company/phone/save', fn() => DashboardController::companyPhoneSave()], ['POST', '/admin/company/phone/delete', fn() => DashboardController::companyPhoneDelete()], + ['POST', '/admin/company/phones/sync', fn() => DashboardController::companyPhonesSync()], // ─── Endpoints API por empresa ───────────────────────────────────────── ['POST', '/admin/company/endpoint/save', fn() => DashboardController::companyEndpointSave()],