diff --git a/src/pages/SettingsPage.js b/src/pages/SettingsPage.js index be1bb8b..0de8739 100644 --- a/src/pages/SettingsPage.js +++ b/src/pages/SettingsPage.js @@ -2,7 +2,7 @@ import { isDarkTheme, toggleTheme } from '../services/theme.js'; import { icons } from '../services/icons.js'; import { apiGet, apiPut } from '../services/apiClient.js'; import { showToast } from '../services/toast.js'; -import { encryptVeriFactuPassword, formatVeriFactuError, getVeriFactuFormats, getVeriFactuHealth, registerVeriFactuCertificate, saveVeriFactuToken, getVeriFactuToken, clearVeriFactuToken } from '../services/verifactu.js'; +import { encryptVeriFactuPassword, formatVeriFactuError, getVeriFactuFormats, getVeriFactuHealth, getVeriFactuTokenStatus, initVeriFactuStatus, registerVeriFactuCertificate } from '../services/verifactu.js'; function decodeTokenPayload(token) { try { @@ -155,8 +155,7 @@ export function renderSettingsPage() {
- - +

@@ -203,27 +202,19 @@ export function renderSettingsPage() { const verifactuCertName = container.querySelector('#verifactu-cert-name'); const verifactuCertFile = container.querySelector('#verifactu-cert-file'); const verifactuCertPassword = container.querySelector('#verifactu-cert-password'); - const clearTokenBtn = container.querySelector('#verifactu-clear-token-btn'); - - const renderVeriFactuTokenStatus = () => { - const token = getVeriFactuToken(); - if (token) { - verifactuStatus.textContent = `Token activo: ${token.slice(0, 8)}...`; - clearTokenBtn.style.display = ''; - } else { - clearTokenBtn.style.display = 'none'; + async function renderVeriFactuTokenStatus() { + try { + const status = await getVeriFactuTokenStatus(); + verifactuStatus.textContent = status?.active + ? 'Certificado activo. El sistema está listo para facturar.' + : 'Sin certificado registrado.'; + } catch { + verifactuStatus.textContent = ''; } - }; + } renderVeriFactuTokenStatus(); - clearTokenBtn.addEventListener('click', () => { - clearVeriFactuToken(); - verifactuStatus.textContent = 'Token eliminado.'; - clearTokenBtn.style.display = 'none'; - showToast('Token de VeriFactu eliminado', 'success'); - }); - verifactuCertFile.addEventListener('change', () => { const file = verifactuCertFile.files?.[0]; if (!file) return; @@ -354,13 +345,9 @@ export function renderSettingsPage() { return; } - if (result.token) { - saveVeriFactuToken(result.token); - renderVeriFactuTokenStatus(); - } - const tokenHint = result.token ? ` Token: ${result.token.slice(0, 8)}...` : ''; - verifactuStatus.textContent = `Certificado registrado.${tokenHint}`; + verifactuStatus.textContent = 'Certificado registrado. El sistema está listo para facturar.'; showToast('Certificado registrado en VeriFactu', 'success'); + initVeriFactuStatus(); } catch (error) { const errorMessage = formatVeriFactuError(error); verifactuStatus.textContent = `Error al registrar certificado: ${errorMessage}`; diff --git a/src/services/session.js b/src/services/session.js index 3b8be00..75e8b03 100644 --- a/src/services/session.js +++ b/src/services/session.js @@ -1,4 +1,5 @@ import { auth } from './auth.js'; +import { initVeriFactuStatus, resetVeriFactuStatus } from './verifactu.js'; const SESSION_TIMEOUT_MS = Number(import.meta.env.VITE_SESSION_TIMEOUT_MS || 15 * 60 * 1000); const SESSION_WARNING_MS = Number(import.meta.env.VITE_SESSION_WARNING_MS || 60 * 1000); @@ -166,11 +167,13 @@ function bindAuthListeners() { window.addEventListener('auth:login', () => { removeWarningOverlay(); resetSessionTimers(); + initVeriFactuStatus(); }); window.addEventListener('auth:logout', () => { removeWarningOverlay(); clearTimers(); + resetVeriFactuStatus(); }); } diff --git a/src/services/verifactu.js b/src/services/verifactu.js index 80b510a..97ebdfa 100644 --- a/src/services/verifactu.js +++ b/src/services/verifactu.js @@ -1,22 +1,30 @@ import forge from 'node-forge'; -import { apiGet, apiPost } from './apiClient.js'; +import { apiGet, apiPost, apiRequest } from './apiClient.js'; + +const VERIFACTU_URL = import.meta.env.VITE_VERIFACTU_URL ?? 'http://localhost:6789'; let cachedPublicKeyPem = null; +let verifactuActive = false; +let verifactuToken = null; -const VERIFACTU_TOKEN_KEY = 'verifactu_cert_token'; +export function isVeriFactuActive() { + return verifactuActive; +} -export function saveVeriFactuToken(token) { - if (token) { - localStorage.setItem(VERIFACTU_TOKEN_KEY, token); +export async function initVeriFactuStatus() { + try { + const data = await apiGet('/api/VeriFactu/token'); + verifactuActive = data?.active === true; + verifactuToken = data?.token ?? null; + } catch { + verifactuActive = false; + verifactuToken = null; } } -export function getVeriFactuToken() { - return localStorage.getItem(VERIFACTU_TOKEN_KEY) || null; -} - -export function clearVeriFactuToken() { - localStorage.removeItem(VERIFACTU_TOKEN_KEY); +export function resetVeriFactuStatus() { + verifactuActive = false; + verifactuToken = null; } const VERIFACTU_ERROR_MESSAGES = { @@ -101,10 +109,26 @@ export function formatVeriFactuError(errorLike) { return raw; } +export async function getVeriFactuTokenStatus() { + return apiGet('/api/VeriFactu/token-status'); +} + export async function sendVeriFactuInvoice(payload) { - return apiPost('/api/VeriFactu/facturas', payload); + if (!verifactuToken) throw new Error('No hay token de VeriFactu activo'); + return apiRequest(`${VERIFACTU_URL}/api/v1/facturas`, { + method: 'POST', + auth: false, + headers: { Authorization: `Bearer ${verifactuToken}` }, + body: payload + }); } export async function cancelVeriFactuInvoice(payload) { - return apiPost('/api/VeriFactu/facturas/anular', payload); + if (!verifactuToken) throw new Error('No hay token de VeriFactu activo'); + return apiRequest(`${VERIFACTU_URL}/api/v1/facturas/anular`, { + method: 'POST', + auth: false, + headers: { Authorization: `Bearer ${verifactuToken}` }, + body: payload + }); } \ No newline at end of file