Files
Lizandro GuarnizoandClaude Sonnet 4.6 724179a3c6 feat: perfil por numero — trabajador vinculado y modulos permitidos
Dos perfiles, sin agregar ningun campo para distinguirlos:

- Con tercero vinculado en el ERP, el numero es de un trabajador: from_phone
  pre-llena empleado_id y el flujo se saltea el buscador. Sale gratis porque
  empleados y terceros son la misma tabla, asi que el id sirve tal cual.
- Sin vinculo es supervisor y elige de quien es el registro.

Los modulos habilitados (ciclos, ausentismos, produccion, pluviometria) llegan
del ERP y filtran las filas de menu. Las filas sin modulo declarado no se tocan,
asi la navegacion queda intacta.

Se mantiene la convencion de las fincas: nada marcado significa todo. Los
numeros que ya existen siguen igual sin migrar nada.

Requiere en la base del bot:
  ALTER TABLE company_phones
    ADD COLUMN tercero_id INT NULL, ADD COLUMN modulos_json TEXT NULL;
El codigo tolera que no existan todavia.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-11 20:21:32 -05:00

125 lines
4.4 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, tercero_id, modulos_json, is_active)
VALUES (?, ?, ?, ?, ?, ?, 1)
ON DUPLICATE KEY UPDATE
label = VALUES(label),
permission_type = VALUES(permission_type),
tercero_id = VALUES(tercero_id),
modulos_json = VALUES(modulos_json),
is_active = 1
");
$activeNumbers = [];
foreach ($numeros as $n) {
$waNumber = trim($n['wa_number'] ?? '');
if ($waNumber === '') continue;
// tercero_id vinculado = perfil trabajador: el bot no le pregunta
// de quién es el registro. Sin él, es supervisor y elige.
$tercero = !empty($n['tercero_id']) ? (int)$n['tercero_id'] : null;
$modulos = (array)($n['modulos'] ?? []);
$upsert->execute([
$companyId,
$waNumber,
trim($n['nombre'] ?? ''),
(int)($n['permiso'] ?? 1),
$tercero,
$modulos ? json_encode($modulos) : null,
]);
$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,
];
}
}