/** * Billing UI — Spec 023 + VM123 deep-links (Spec 027 Fase 3) */ const DeskBilling = (() => { const API = '/api'; function esc(s) { return String(s ?? '').replace(/&/g, '&').replace(//g, '>'); } 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 vm123LinksHtml(vm123, acc) { const links = vm123?.links || {}; const perms = vm123?.permissions || {}; const foss = links.foss || {}; const odoo = links.odoo || {}; const op = links.openpanel || {}; const fossHint = vm123?.foss?.client_id ? ` · cliente #${vm123.foss.client_id}` : ''; const odooHint = vm123?.odoo?.partner_name ? ` · ${vm123.odoo.partner_name}` : ''; const parts = [ `FOSSBilling 💳${esc(fossHint)}`, `Odoo${esc(odooHint)}`, ]; if (perms.can_foss_admin || perms.can_openpanel_autologin) { parts.push(`OpenAdmin`); } return parts.join(' · '); } async function openAccountModal(domain) { closeModal(); const acc = await api(`/v1/billing/accounts/by-domain/${encodeURIComponent(domain)}`); let vm123 = null; try { const q = new URLSearchParams({ domain }); if (acc.email_billing) q.set('email', acc.email_billing); vm123 = await api(`/v1/vm123/links/client?${q}`); } catch { vm123 = null; } const canManage = typeof canManageBilling === 'function' ? canManageBilling() : canManageVm112Domains?.(); 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-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 (state.view === 'overview-home') await renderOverviewHome(); }); } return { openAccountModal, closeModal }; })(); window.DeskBilling = DeskBilling;