From 4dea9ab28a1dfa9333ddf9dd7c5e895bbbdd6ab5 Mon Sep 17 00:00:00 2001 From: VPS 4 Builder Date: Mon, 6 Jul 2026 17:24:16 +0200 Subject: [PATCH] =?UTF-8?q?fix(newwhats):=20papel=20do=20n=C3=BAmero=20no?= =?UTF-8?q?=20/wa-inbox=20p/=20usu=C3=A1rio=20sem=20conta=20no=20motor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Os papéis (sec_numbers) são resolvidos no motor pela conta (x-nw-email). Um usuário que só existe no scoreodonto (ex.: recepcionista) não tem conta no motor, então buscar os papéis com o e-mail DELE retorna "conta não encontrada" → todos os números liberados apareciam como "Sem papel definido". Agora o papel de cada sessão liberada é buscado com o e-mail do DONO da sessão (cache por e-mail). Verificado: recep passa a ver o número como role=clinic ("Clínica / Recepção · Rui Cesar"). Co-Authored-By: Claude Opus 4.8 --- backend/newwhats/proxy.js | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/backend/newwhats/proxy.js b/backend/newwhats/proxy.js index 5f333c0..2c994dd 100644 --- a/backend/newwhats/proxy.js +++ b/backend/newwhats/proxy.js @@ -301,29 +301,39 @@ export function createAccountsRoute(pool) { }; try { - // Papéis: sec_numbers são globais no motor — um fetch, indexado por instance_id. - const numbers = await motorGet('/secretaria/numbers', email); - const roleOf = new Map(numbers.map((n) => [n.instance_id, n])); - const meta = (instanceId, fallbackName) => { - const n = roleOf.get(instanceId) || {}; + // Papéis (sec_numbers) são resolvidos no motor pela CONTA (x-nw-email). Um + // usuário sem conta no motor (ex.: recepcionista que só existe no scoreodonto) + // não tem números próprios — então o papel de cada número LIBERADO precisa ser + // buscado com o e-mail do DONO da sessão, não do usuário logado. Cache por e-mail. + const numbersCache = new Map(); + const numbersFor = async (asEmail) => { + if (!numbersCache.has(asEmail)) { + const nums = await motorGet('/secretaria/numbers', asEmail); + numbersCache.set(asEmail, new Map(nums.map((n) => [n.instance_id, n]))); + } + return numbersCache.get(asEmail); + }; + const metaFrom = (roleMap, instanceId, fallbackName) => { + const n = roleMap.get(instanceId) || {}; return { role: n.role || null, label: n.label || fallbackName || null, area: n.area || null, notes: n.notes || null }; }; const out = []; const seen = new Set(); - const push = (s, extra) => { + const pushWith = (s, roleMap, extra) => { if (!s || seen.has(s.id)) return; seen.add(s.id); out.push({ instanceId: s.id, phone: s.phone || null, name: s.name || null, status: s.status || null, avatar: s.avatar || null, - ...meta(s.id, s.name), ...extra, + ...metaFrom(roleMap, s.id, s.name), ...extra, }); }; - // 1) Sessões PRÓPRIAS (conta do próprio usuário no motor). + // 1) Sessões PRÓPRIAS (conta do próprio usuário no motor) — papel da própria conta. + const ownRoles = await numbersFor(email); for (const s of await motorGet('/sessions', email)) { - push(s, { clinicaId: null, ownerEmail: email, ownerNome: null, own: true, canInbox: true }); + pushWith(s, ownRoles, { clinicaId: null, ownerEmail: email, ownerNome: null, own: true, canInbox: true }); } // 2) Sessões LIBERADAS por outros donos (can_inbox por sessão). @@ -343,8 +353,9 @@ export function createAccountsRoute(pool) { const { rows } = await pool.query('SELECT nome FROM usuarios WHERE id = $1', [owner.ownerId]); ownerNome = rows[0]?.nome || null; } catch { /* opcional */ } + const ownerRoles = await numbersFor(owner.email); // papéis dos números vêm da conta do DONO for (const s of await motorGet('/sessions', owner.email)) { - if (allowed.has(s.id)) push(s, { clinicaId, ownerEmail: owner.email, ownerNome, own: false, canInbox: true }); + if (allowed.has(s.id)) pushWith(s, ownerRoles, { clinicaId, ownerEmail: owner.email, ownerNome, own: false, canInbox: true }); } }