Configuración IA: selector de gremio en condiciones de cobertura (combinable con compañía)

This commit is contained in:
2026-08-28 21:20:31 +00:00
parent bc519a76aa
commit d6e245ad0d

View File

@@ -244,8 +244,8 @@
</div> </div>
<div class="p-4 border-b border-slate-100 mb-2 bg-slate-50"> <div class="p-4 border-b border-slate-100 mb-2 bg-slate-50">
<label class="block text-sm font-medium text-gray-700">Condiciones de Cobertura por Compañía (Opcional)</label> <label class="block text-sm font-medium text-gray-700">Condiciones de Cobertura por Compañía y/o Gremio (Opcional)</label>
<p class="text-xs text-gray-500 mb-2">Cuando el cliente pregunte por costes, materiales o qué cubre el seguro, la IA usará el texto de la compañía que coincida con el expediente. La palabra clave se busca dentro del campo "Compañía" del expediente (sin importar mayúsculas ni el resto del texto alrededor).</p> <p class="text-xs text-gray-500 mb-2">Cuando el cliente pregunte por costes, materiales o qué cubre el seguro, la IA usará el texto que coincida con el expediente. Puedes poner solo compañía, solo gremio (manitas, electricista, fontanería...), o ambos a la vez para que las condiciones cambien según el tipo de servicio dentro de una misma compañía. Si hay varias reglas que coinciden, se usa la más específica (compañía + gremio combinados).</p>
<div id="detectedCompaniesBox" class="hidden mb-3"> <div id="detectedCompaniesBox" class="hidden mb-3">
<p class="text-[10px] font-black text-slate-400 uppercase tracking-widest mb-2">Buscar compañía vista en tus expedientes</p> <p class="text-[10px] font-black text-slate-400 uppercase tracking-widest mb-2">Buscar compañía vista en tus expedientes</p>
@@ -992,10 +992,11 @@
let currentTemplateType = null; let currentTemplateType = null;
let localGuilds = []; let localGuilds = [];
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", async () => {
if (!localStorage.getItem("token")) window.location.href = "index.html"; if (!localStorage.getItem("token")) window.location.href = "index.html";
showTab('templates'); showTab('templates');
loadTemplates(); loadTemplates();
await loadGuildsForCoverage();
loadWaSettings(); loadWaSettings();
loadDetectedCompanies(); loadDetectedCompanies();
}); });
@@ -1196,7 +1197,7 @@
} }
document.getElementById('coverageRulesList').innerHTML = ""; document.getElementById('coverageRulesList').innerHTML = "";
(s.coverage_rules || []).forEach(r => addCoverageRule(r.keyword, r.text)); (s.coverage_rules || []).forEach(r => addCoverageRule(r.keyword, r.text, r.gremio_id));
document.getElementById('cfg_delay').checked = s.wa_delay_enabled !== false; document.getElementById('cfg_delay').checked = s.wa_delay_enabled !== false;
document.getElementById('cfg_evt_welcome').checked = s.wa_evt_welcome || false; document.getElementById('cfg_evt_welcome').checked = s.wa_evt_welcome || false;
@@ -1208,23 +1209,42 @@
} catch(e) { console.error("Error cargando ajustes WA", e); } } catch(e) { console.error("Error cargando ajustes WA", e); }
} }
// 🧾 Condiciones de cobertura por compañía: cada fila es { keyword, text }. La IA // 🧾 Condiciones de cobertura por compañía y/o gremio: cada fila es
// busca esta "keyword" (sin mayúsculas ni tildes) DENTRO del campo Compañía del // { keyword, gremio_id, text }. La "keyword" (opcional) se busca sin mayúsculas ni
// expediente, así que da igual si viene envuelta en texto de Multiasistencia, // tildes DENTRO del campo Compañía del expediente, así que da igual si viene envuelta
// HomeServe, etc. — con que contenga la palabra clave (ej. "santander") es suficiente. // en texto de Multiasistencia, HomeServe, etc. El "gremio_id" (opcional) es el id real
function addCoverageRule(keyword = "", text = "") { // de uno de tus gremios (Electricista, Fontanería, Manitas...), para que las
// condiciones cambien según el tipo de servicio. Puedes dejar cualquiera de los dos
// vacío: solo compañía, solo gremio, o ambos combinados (más específico).
let guildsCache = [];
async function loadGuildsForCoverage() {
try {
const res = await fetch(`${API_URL}/guilds`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } });
const data = await res.json();
guildsCache = data.guilds || [];
} catch (e) { console.error("Error cargando gremios", e); guildsCache = []; }
}
function addCoverageRule(keyword = "", text = "", gremioId = "") {
const wrap = document.createElement('div'); const wrap = document.createElement('div');
wrap.className = "coverage-rule-row bg-white border border-slate-200 rounded-lg p-3 space-y-2"; wrap.className = "coverage-rule-row bg-white border border-slate-200 rounded-lg p-3 space-y-2";
const gremioOptions = ['<option value="">Todos los gremios</option>']
.concat(guildsCache.map(g => `<option value="${g.id}">${g.name}</option>`))
.join('');
wrap.innerHTML = ` wrap.innerHTML = `
<div class="flex items-center gap-2"> <div class="flex items-center gap-2 flex-wrap">
<input type="text" class="cr-keyword flex-1 border-gray-300 rounded-md shadow-sm text-sm p-2 font-bold" placeholder="Palabra clave (ej: santander)"> <input type="text" class="cr-keyword flex-1 min-w-[140px] border-gray-300 rounded-md shadow-sm text-sm p-2 font-bold" placeholder="Palabra clave de compañía (opcional, ej: santander)">
<select class="cr-gremio border-gray-300 rounded-md shadow-sm text-xs p-2 font-bold text-slate-600">${gremioOptions}</select>
<button type="button" onclick="this.closest('.coverage-rule-row').remove()" class="text-rose-500 hover:text-rose-700 p-1 shrink-0"><i data-lucide="trash-2" class="w-4 h-4"></i></button> <button type="button" onclick="this.closest('.coverage-rule-row').remove()" class="text-rose-500 hover:text-rose-700 p-1 shrink-0"><i data-lucide="trash-2" class="w-4 h-4"></i></button>
</div> </div>
<textarea class="cr-text w-full border-gray-300 rounded-md shadow-sm text-xs p-2" rows="2" placeholder="Condiciones de cobertura (ej: Cubre hasta 30€ en materiales y 2h de mano de obra. A partir de ahí lo paga el cliente)"></textarea> <textarea class="cr-text w-full border-gray-300 rounded-md shadow-sm text-xs p-2" rows="2" placeholder="Condiciones de cobertura (ej: Cubre hasta 30€ en materiales y 2h de mano de obra. A partir de ahí lo paga el cliente)"></textarea>
<p class="text-[10px] text-slate-400">Deja la palabra clave vacía para que aplique a cualquier compañía, o "Todos los gremios" para que aplique sin importar el tipo de servicio.</p>
`; `;
document.getElementById('coverageRulesList').appendChild(wrap); document.getElementById('coverageRulesList').appendChild(wrap);
wrap.querySelector('.cr-keyword').value = keyword; wrap.querySelector('.cr-keyword').value = keyword;
wrap.querySelector('.cr-text').value = text; wrap.querySelector('.cr-text').value = text;
wrap.querySelector('.cr-gremio').value = gremioId || "";
if (window.lucide) lucide.createIcons(); if (window.lucide) lucide.createIcons();
} }
@@ -1294,9 +1314,10 @@
const coverageRules = [...document.querySelectorAll('#coverageRulesList .coverage-rule-row')] const coverageRules = [...document.querySelectorAll('#coverageRulesList .coverage-rule-row')]
.map(row => ({ .map(row => ({
keyword: row.querySelector('.cr-keyword').value.trim(), keyword: row.querySelector('.cr-keyword').value.trim(),
gremio_id: row.querySelector('.cr-gremio').value.trim(),
text: row.querySelector('.cr-text').value.trim() text: row.querySelector('.cr-text').value.trim()
})) }))
.filter(r => r.keyword && r.text); .filter(r => (r.keyword || r.gremio_id) && r.text);
const settings = { const settings = {
wa_ai_enabled: document.getElementById('cfg_ai_enabled').checked, wa_ai_enabled: document.getElementById('cfg_ai_enabled').checked,