doli-front/src/services/verifactu.js

94 lines
3.4 KiB
JavaScript

import forge from 'node-forge';
import { apiGet, apiPost } from './apiClient.js';
let cachedPublicKeyPem = null;
const VERIFACTU_ERROR_MESSAGES = {
missing_fields: 'Faltan campos obligatorios para registrar el certificado.',
invalid_json: 'La peticion enviada a VeriFactu no tiene un JSON valido.',
invalid_password_encrypted: 'La contraseña cifrada no tiene un formato valido.',
decrypt_failed: 'No se pudo descifrar la contraseña del certificado.',
file_not_found: 'No se encontro el archivo del certificado.',
invalid_password_or_format: 'La contraseña del .p12 es incorrecta o el archivo no es valido.',
certificate_not_yet_valid: 'El certificado aun no es valido por fecha.',
certificate_expired: 'El certificado ha caducado.',
temp_storage_failed: 'No se pudo guardar el certificado temporalmente.',
storage_failed: 'No se pudo guardar el certificado de forma permanente.',
token_generation_failed: 'No se pudo generar el token de sesion del certificado.',
hash_storage_error: 'Error leyendo el hash previo de facturacion.',
hash_save_error: 'Error guardando el hash de la factura.',
internal_server_error: 'VeriFactu devolvio un error interno del servidor.'
};
export async function getVeriFactuHealth() {
return apiGet('/api/VeriFactu/health', { auth: false });
}
export async function getVeriFactuPublicKey() {
return apiGet('/api/VeriFactu/public-key', { auth: false });
}
async function getVeriFactuPublicKeyPem() {
if (cachedPublicKeyPem) {
return cachedPublicKeyPem;
}
const response = await getVeriFactuPublicKey();
if (!response?.public_key) {
throw new Error('La API no devolvio la clave publica de VeriFactu');
}
cachedPublicKeyPem = atob(response.public_key);
return cachedPublicKeyPem;
}
export async function encryptVeriFactuPassword(password) {
if (!password) {
throw new Error('La contraseña del certificado no puede estar vacia');
}
console.log('[ENCRYPT] Input password:', password);
const publicKeyPem = await getVeriFactuPublicKeyPem();
console.log('[ENCRYPT] Got public key');
const publicKey = forge.pki.publicKeyFromPem(publicKeyPem);
console.log('[ENCRYPT] Parsed public key');
const encryptedBytes = publicKey.encrypt(forge.util.encodeUtf8(password), 'RSAES-PKCS1-V1_5');
console.log('[ENCRYPT] RSA encrypted, bytes length:', encryptedBytes.length);
const result = forge.util.encode64(encryptedBytes);
console.log('[ENCRYPT] Base64 encoded, result length:', result.length);
return result;
}
export async function getVeriFactuFormats() {
return apiGet('/api/VeriFactu/formats', { auth: false });
}
export async function registerVeriFactuCertificate(payload) {
return apiPost('/api/VeriFactu/certificates/register', payload);
}
export function formatVeriFactuError(errorLike) {
const raw = String(errorLike?.message || errorLike || '').trim();
if (!raw) {
return 'Error desconocido en VeriFactu.';
}
// Preserve backend text format for these errors to avoid changing JSON/detail structure.
if (raw === 'invalid_json' || raw.startsWith('validation_failed') || raw.startsWith('aeat_error:') || raw.startsWith('aeat_fault:')) {
return raw;
}
if (VERIFACTU_ERROR_MESSAGES[raw]) {
return VERIFACTU_ERROR_MESSAGES[raw];
}
return raw;
}
export async function sendVeriFactuInvoice(payload) {
return apiPost('/api/VeriFactu/facturas', payload);
}
export async function cancelVeriFactuInvoice(payload) {
return apiPost('/api/VeriFactu/facturas/anular', payload);
}