diff --git a/services/NormalBot.php b/services/NormalBot.php index 281d3df..4f816b1 100644 --- a/services/NormalBot.php +++ b/services/NormalBot.php @@ -448,6 +448,67 @@ class NormalBot } } + /** + * Perfil sincronizado del numero: con quien esta vinculado y que modulos + * tiene habilitados. Tolera que las columnas aun no existan. + */ + private static function perfilDelNumero(array $company, string $waNumber): array + { + static $cache = []; + $clave = $company['id'] . '|' . $waNumber; + if (isset($cache[$clave])) return $cache[$clave]; + + $vacio = ['tercero_id' => null, 'modulos' => []]; + if ($waNumber === '') return $vacio; + + try { + $stmt = db()->prepare( + "SELECT tercero_id, modulos_json FROM company_phones WHERE company_id = ? AND wa_number = ? LIMIT 1" + ); + $stmt->execute([(int)$company['id'], $waNumber]); + $row = $stmt->fetch(); + } catch (\PDOException $e) { + return $vacio; // columnas aun sin crear + } + if (!$row) return $vacio; + + return $cache[$clave] = [ + 'tercero_id' => $row['tercero_id'] ?: null, + 'modulos' => json_decode((string)($row['modulos_json'] ?? ''), true) ?: [], + ]; + } + + /** + * Quita del menu las filas de modulos que este numero no tiene habilitados. + * Sin modulos declarados no se filtra nada: la ausencia significa "todos", + * misma convencion que las fincas. + */ + private static function filtrarMenuPorModulos(array $menu, array $company, string $waNumber): array + { + $perfil = self::perfilDelNumero($company, $waNumber); + if (!$perfil['modulos']) return $menu; + + $permitidos = array_merge( + (array)($perfil['modulos']['descarga'] ?? []), + (array)($perfil['modulos']['carga'] ?? []) + ); + + foreach ($menu['sections'] ?? [] as $i => $sec) { + $filas = array_values(array_filter($sec['rows'] ?? [], fn($r) => + !isset($r['modulo']) || in_array($r['modulo'], $permitidos, true) + )); + $menu['sections'][$i]['rows'] = $filas; + } + $menu['sections'] = array_values(array_filter($menu['sections'] ?? [], fn($s) => !empty($s['rows']))); + + foreach ($menu['buttons'] ?? [] as $i => $btn) { + if (isset($btn['modulo']) && !in_array($btn['modulo'], $permitidos, true)) unset($menu['buttons'][$i]); + } + if (isset($menu['buttons'])) $menu['buttons'] = array_values($menu['buttons']); + + return $menu; + } + /** * Guarda la opción elegida con su etiqueta, para poder mostrarle al usuario * en qué finca/grupo está parado sin tener que volver a consultar la API. @@ -997,6 +1058,18 @@ class NormalBot $collected = []; $startIdx = 0; + + // from_phone: el dato sale del perfil del numero, no se pregunta. Con un + // tercero vinculado el trabajador reporta lo suyo y el bot no le pide + // que se busque a si mismo; sin vinculo es supervisor y elige. + $perfil = self::perfilDelNumero($company, $context['from'] ?? ''); + foreach ($fields as $f) { + $origen = $f['from_phone'] ?? ''; + if ($origen !== '' && !empty($perfil[$origen])) { + $collected[$f['key']] = (string)$perfil[$origen]; + } + } + if (!empty($entities)) { foreach ($fields as $i => $field) { $fKey = $field['key'] ?? ''; @@ -1015,6 +1088,10 @@ class NormalBot } } + while ($startIdx < count($fields) && isset($collected[$fields[$startIdx]['key'] ?? ''])) { + $startIdx++; + } + $meta['__cap'] = [ 'fields' => $fields, 'index' => $startIdx, @@ -2097,6 +2174,7 @@ class NormalBot private static function buildMenuResponse(array $menu, string $to, array $company, ?int $ctxId = null): ?array { + $menu = self::filtrarMenuPorModulos($menu, $company, $to); $menu = self::aplicarVarsMenu($menu, $ctxId, $company); $menuType = $menu['type'] ?? 'list'; diff --git a/services/PhoneSync.php b/services/PhoneSync.php index e4b2831..8f73dfb 100644 --- a/services/PhoneSync.php +++ b/services/PhoneSync.php @@ -71,11 +71,13 @@ class PhoneSync $db = db(); $upsert = $db->prepare(" - INSERT INTO company_phones (company_id, wa_number, label, permission_type, is_active) - VALUES (?, ?, ?, ?, 1) + 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 "); @@ -84,11 +86,18 @@ class PhoneSync $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; } diff --git a/setup/seed_palmas.php b/setup/seed_palmas.php index e0f7bd3..1c24a55 100644 --- a/setup/seed_palmas.php +++ b/setup/seed_palmas.php @@ -97,9 +97,9 @@ $configJson = [ [ 'title' => 'Informes', 'rows' => [ - ['id' => 'submenu_produccion', 'title' => '🌿 Producción', 'description' => 'Informes de producción'], - ['id' => 'submenu_ciclos', 'title' => '🔄 Ciclos', 'description' => 'Ciclos de campo'], - ['id' => 'submenu_ausentismos', 'title' => '👥 Ausentismos', 'description' => 'Faltas y novedades'], + ['id' => 'submenu_produccion', 'modulo' => 'produccion', 'title' => '🌿 Producción', 'description' => 'Informes de producción'], + ['id' => 'submenu_ciclos', 'modulo' => 'ciclos', 'title' => '🔄 Ciclos', 'description' => 'Ciclos de campo'], + ['id' => 'submenu_ausentismos', 'modulo' => 'ausentismos', 'title' => '👥 Ausentismos', 'description' => 'Faltas y novedades'], ], ], ], @@ -230,9 +230,9 @@ $configJson = [ [ 'title' => 'Opciones', 'rows' => [ - ['id' => 'registrar_ausentismo', 'title' => '👥 Ausentismo', 'description' => 'Registrar falta, incapacidad o permiso'], - ['id' => 'registrar_pluviometria','title' => '🌧️ Pluviometría', 'description' => 'Milímetros por finca · pronto formulario'], - ['id' => 'registrar_ciclo', 'title' => '🔄 Ciclos', 'description' => 'Abrir o cerrar lotes · pronto formulario'], + ['id' => 'registrar_ausentismo', 'modulo' => 'ausentismos', 'title' => '👥 Ausentismo', 'description' => 'Registrar falta, incapacidad o permiso'], + ['id' => 'registrar_pluviometria','modulo' => 'pluviometria', 'title' => '🌧️ Pluviometría', 'description' => 'Milímetros por finca · pronto formulario'], + ['id' => 'registrar_ciclo', 'modulo' => 'ciclos', 'title' => '🔄 Ciclos', 'description' => 'Abrir o cerrar lotes · pronto formulario'], ], ], ], @@ -416,6 +416,8 @@ $configJson = [ 'key' => 'empleado_id', 'label' => 'Trabajador', 'type' => 'lookup', + // Numero vinculado a un trabajador: no se le pregunta + 'from_phone' => 'tercero_id', 'prompt' => '👤 Escribe el nombre o documento del trabajador:', 'lookup_endpoint_key' => 'empleados_buscar_dn', 'lookup_param' => 'filtro', @@ -560,9 +562,9 @@ $configJson = [ [ 'title' => 'Opciones', 'rows' => [ - ['id' => 'registrar_ausentismo', 'title' => '👥 Ausentismo', 'description' => 'Registrar falta, incapacidad o permiso'], - ['id' => 'registrar_pluviometria','title' => '🌧️ Pluviometría', 'description' => 'Milímetros por finca · pronto formulario'], - ['id' => 'registrar_ciclo', 'title' => '🔄 Ciclos', 'description' => 'Abrir o cerrar lotes · pronto formulario'], + ['id' => 'registrar_ausentismo', 'modulo' => 'ausentismos', 'title' => '👥 Ausentismo', 'description' => 'Registrar falta, incapacidad o permiso'], + ['id' => 'registrar_pluviometria','modulo' => 'pluviometria', 'title' => '🌧️ Pluviometría', 'description' => 'Milímetros por finca · pronto formulario'], + ['id' => 'registrar_ciclo', 'modulo' => 'ciclos', 'title' => '🔄 Ciclos', 'description' => 'Abrir o cerrar lotes · pronto formulario'], ], ], ], @@ -592,9 +594,9 @@ $configJson = [ [ 'title' => 'Informes', 'rows' => [ - ['id' => 'submenu_produccion', 'title' => '🌿 Producción', 'description' => 'Informes de producción'], - ['id' => 'submenu_ciclos', 'title' => '🔄 Ciclos', 'description' => 'Ciclos de campo'], - ['id' => 'submenu_ausentismos', 'title' => '👥 Ausentismos', 'description' => 'Faltas y novedades'], + ['id' => 'submenu_produccion', 'modulo' => 'produccion', 'title' => '🌿 Producción', 'description' => 'Informes de producción'], + ['id' => 'submenu_ciclos', 'modulo' => 'ciclos', 'title' => '🔄 Ciclos', 'description' => 'Ciclos de campo'], + ['id' => 'submenu_ausentismos', 'modulo' => 'ausentismos', 'title' => '👥 Ausentismos', 'description' => 'Faltas y novedades'], ], ], ],