api_base_url guarda el Graph API de WhatsApp (lo fija el propio seed), asi que el cron armaba https://graph.facebook.com/v22.0/php/controller/... y recibia 401 cada 5 minutos desde siempre. El endpoint numeros_dn ya estaba registrado con la URL absoluta correcta; ahora la sincronizacion lo usa como el resto de llamadas al ERP. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
116 lines
3.9 KiB
PHP
116 lines
3.9 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
class PhoneSync
|
|
{
|
|
/** Endpoint registrado en company_endpoints que devuelve los números habilitados */
|
|
private const ENDPOINT_KEY = 'numeros_dn';
|
|
|
|
public static function syncAll(): array
|
|
{
|
|
$companies = CompanyRepository::findAll();
|
|
$results = [];
|
|
|
|
foreach ($companies as $company) {
|
|
$results[] = self::syncCompany($company);
|
|
}
|
|
|
|
return $results;
|
|
}
|
|
|
|
public static function syncCompany(array $company): array
|
|
{
|
|
$companyId = (int)$company['id'];
|
|
$name = $company['name'] ?? "company {$companyId}";
|
|
$apiKey = $company['api_key'] ?? '';
|
|
|
|
// La URL sale de company_endpoints, igual que el resto de llamadas al ERP.
|
|
// api_base_url no sirve acá: guarda el Graph API de WhatsApp, no el ERP.
|
|
$stmt = db()->prepare(
|
|
"SELECT url FROM company_endpoints WHERE company_id = ? AND endpoint_key = ? AND is_active = 1 LIMIT 1"
|
|
);
|
|
$stmt->execute([$companyId, self::ENDPOINT_KEY]);
|
|
$url = (string)($stmt->fetchColumn() ?: '');
|
|
|
|
if ($url === '') {
|
|
return ['company' => $name, 'status' => 'skip', 'reason' => 'sin endpoint ' . self::ENDPOINT_KEY];
|
|
}
|
|
|
|
$ch = curl_init($url);
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_TIMEOUT => 15,
|
|
CURLOPT_HTTPHEADER => [
|
|
'Accept: application/json',
|
|
'Authorization: Bearer ' . $apiKey,
|
|
'X-API-Key: ' . $apiKey,
|
|
],
|
|
]);
|
|
$body = curl_exec($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
$curlErr = curl_error($ch);
|
|
curl_close($ch);
|
|
|
|
if ($curlErr !== '') {
|
|
return ['company' => $name, 'status' => 'error', 'reason' => 'cURL: ' . $curlErr];
|
|
}
|
|
if ($httpCode !== 200) {
|
|
return ['company' => $name, 'status' => 'error', 'reason' => "HTTP {$httpCode}"];
|
|
}
|
|
|
|
$data = json_decode((string)$body, true);
|
|
if (!is_array($data) || ($data['status'] ?? '') !== '1') {
|
|
$msg = $data['mensaje'] ?? $data['message'] ?? 'respuesta inválida';
|
|
return ['company' => $name, 'status' => 'error', 'reason' => $msg];
|
|
}
|
|
|
|
$numeros = $data['numeros'] ?? [];
|
|
if (empty($numeros)) {
|
|
return ['company' => $name, 'status' => 'ok', 'upserted' => 0, 'deactivated' => 0];
|
|
}
|
|
|
|
$db = db();
|
|
$upsert = $db->prepare("
|
|
INSERT INTO company_phones (company_id, wa_number, label, permission_type, is_active)
|
|
VALUES (?, ?, ?, ?, 1)
|
|
ON DUPLICATE KEY UPDATE
|
|
label = VALUES(label),
|
|
permission_type = VALUES(permission_type),
|
|
is_active = 1
|
|
");
|
|
|
|
$activeNumbers = [];
|
|
foreach ($numeros as $n) {
|
|
$waNumber = trim($n['wa_number'] ?? '');
|
|
if ($waNumber === '') continue;
|
|
|
|
$upsert->execute([
|
|
$companyId,
|
|
$waNumber,
|
|
trim($n['nombre'] ?? ''),
|
|
(int)($n['permiso'] ?? 1),
|
|
]);
|
|
$activeNumbers[] = $waNumber;
|
|
}
|
|
|
|
// Deactivate numbers removed from PALMAS360
|
|
$deactivated = 0;
|
|
if (!empty($activeNumbers)) {
|
|
$placeholders = implode(',', array_fill(0, count($activeNumbers), '?'));
|
|
$stmt = $db->prepare("
|
|
UPDATE company_phones SET is_active = 0
|
|
WHERE company_id = ? AND is_active = 1 AND wa_number NOT IN ({$placeholders})
|
|
");
|
|
$stmt->execute(array_merge([$companyId], $activeNumbers));
|
|
$deactivated = $stmt->rowCount();
|
|
}
|
|
|
|
return [
|
|
'company' => $name,
|
|
'status' => 'ok',
|
|
'upserted' => count($activeNumbers),
|
|
'deactivated' => $deactivated,
|
|
];
|
|
}
|
|
}
|