/** * Billing UI — Spec 023 + Spec 043 (conta cliente + activação preview) */ const DeskBilling = (() => { const API = '/api'; const PLAN_OPTIONS = [ { code: 'ligbox-mail-starter', label: 'Mail Starter (10)' }, { code: 'ligbox-mail-business', label: 'Mail Business (25)' }, { code: 'ligbox-mail-enterprise', label: 'Mail Enterprise (50)' }, { code: 'ligbox-mail-custom', label: 'Mail Custom' }, ]; function esc(s) { return String(s ?? '').replace(/&/g, '&').replace(//g, '>'); } function canActivate() { return typeof canManageBilling === 'function' && canManageBilling(); } async function api(path, options = {}) { const res = await fetch(`${API}${path}`, { ...options, headers: { ...authHeaders(), 'Content-Type': 'application/json', ...(options.headers || {}) }, }); if (!res.ok) throw new Error((await res.json().catch(() => ({}))).detail || res.statusText); return res.json(); } function closeModal() { document.querySelector('.billing-modal-backdrop')?.remove(); } function renderMappedBlock(title, obj) { const rows = Object.entries(obj || {}) .filter(([, v]) => v != null && v !== '' && typeof v !== 'object') .map(([k, v]) => `
${esc(k)}
${esc(v)}
`) .join(''); return `

${esc(title)}

${rows || '
sem dados
'}
`; } async function openActivationPreview(accountId, domain, planCode) { const plan = planCode || document.querySelector('[data-billing-plan]')?.value || ''; const qs = plan ? `?plan_code=${encodeURIComponent(plan)}` : ''; const preview = await api(`/v1/billing/accounts/${accountId}/activation-preview${qs}`); const m = preview.mapped || {}; const foss = m.foss_client || {}; const op = m.openpanel || {}; const odoo = m.odoo_partner || {}; const meta = op.metadata || {}; const canGo = preview.can_activate !== false; const backdrop = document.createElement('div'); backdrop.className = 'billing-modal-backdrop'; backdrop.innerHTML = ` `; document.body.appendChild(backdrop); backdrop.addEventListener('click', (e) => { if (e.target === backdrop) closeModal(); }); backdrop.querySelector('[data-billing-close]')?.addEventListener('click', closeModal); backdrop.querySelector('[data-billing-activate-confirm]')?.addEventListener('click', async (e) => { const btn = e.currentTarget; const statusEl = backdrop.querySelector('[data-billing-activate-status]'); btn.disabled = true; btn.textContent = 'A activar…'; try { const res = await fetch(`${API}/v1/billing/accounts/${accountId}/activate`, { method: 'POST', headers: { ...authHeaders(), 'Content-Type': 'application/json' }, body: JSON.stringify({ plan_code: preview.plan_code, config: preview.config, provision_mail: true, }), }); const data = await res.json().catch(() => ({})); if (!res.ok && res.status !== 207) { throw new Error(data.detail || data.message || res.statusText); } const fossOk = data.steps?.foss?.client_id ? '✅' : '⚠️'; const opOk = data.steps?.openpanel?.success || data.steps?.openpanel?.reused ? '✅' : '⚠️'; const odooOk = data.steps?.odoo?.partner_id ? '✅' : '⚠️'; statusEl.innerHTML = `${data.ok ? '✅ Conta activada' : '⚠️ Parcial'} — FOSS ${fossOk} · OP ${opOk} · Odoo ${odooOk}`; if (data.message) statusEl.innerHTML += `
${esc(data.message)}`; btn.textContent = data.ok ? 'Concluído' : 'Concluído com avisos'; if (typeof state !== 'undefined' && state.view === 'overview-home' && typeof renderOverviewHome === 'function') { await renderOverviewHome(); } } catch (err) { statusEl.textContent = err.message || 'Erro na activação'; btn.disabled = false; btn.textContent = 'Tentar novamente'; } }); } async function openAccountModal(domain) { closeModal(); const acc = await api(`/v1/billing/accounts/by-domain/${encodeURIComponent(domain)}`); const planOptions = PLAN_OPTIONS.map( (p) => `` ).join(''); const backdrop = document.createElement('div'); backdrop.className = 'billing-modal-backdrop'; backdrop.innerHTML = ` `; document.body.appendChild(backdrop); backdrop.addEventListener('click', (e) => { if (e.target === backdrop) closeModal(); }); backdrop.querySelector('[data-billing-close]')?.addEventListener('click', closeModal); backdrop.querySelector('[data-billing-activate]')?.addEventListener('click', async (e) => { const btn = e.currentTarget; const id = btn.getAttribute('data-billing-activate'); const dom = btn.getAttribute('data-domain') || domain; const plan = backdrop.querySelector('[data-billing-plan]')?.value || ''; try { await openActivationPreview(id, dom, plan); } catch (err) { alert(err.message || 'Erro ao carregar preview'); } }); backdrop.querySelector('[data-billing-ativate]')?.addEventListener('click', async () => { await api(`/v1/billing/accounts/${acc.id}`, { method: 'PATCH', body: JSON.stringify({ recurrence_active: true, billing_state: 'billing_active' }), }); closeModal(); if (typeof state !== 'undefined' && state.view === 'overview-home' && typeof renderOverviewHome === 'function') { await renderOverviewHome(); } }); } return { openAccountModal, openActivationPreview, closeModal }; })(); window.DeskBilling = DeskBilling;