Actualizar contabilidad.html

This commit is contained in:
2026-03-24 14:45:02 +00:00
parent 7a5c5286ec
commit 8a10bc89b4

View File

@@ -247,69 +247,85 @@
</div> </div>
<div id="pdf-wrapper" class="hidden"> <div id="pdf-wrapper" class="hidden">
<div id="pdf-content" class="p-10 bg-white text-slate-800 font-sans" style="width: 800px; min-height: 1120px; position: relative;"> <div id="pdf-content" class="bg-white text-slate-800 font-sans" style="width: 800px; min-height: 1120px; position: relative; padding: 50px;">
<div class="flex justify-between items-start border-b-2 border-slate-200 pb-6 mb-8"> <div style="display: flex; justify-content: space-between; align-items: flex-start; border-bottom: 2px solid #e2e8f0; padding-bottom: 30px; margin-bottom: 40px;">
<div class="flex items-center gap-4"> <div style="max-width: 250px; max-height: 100px;">
<img id="pdf-company-logo" src="" alt="Logo Empresa" class="h-16 w-auto hidden object-contain"> <img id="pdf-company-logo" src="" alt="Logo Empresa" style="max-width: 100%; max-height: 100px; object-fit: contain; display: none;">
<div> <h2 id="pdf-company-name-fallback" style="margin:0; color:#2563eb; font-size: 24px; font-weight: 900; display: none;">IntegraRepara</h2>
<h1 class="text-3xl font-black text-slate-800 tracking-tight" id="pdf-company-name">IntegraRepara</h1> </div>
<p class="text-xs text-slate-500 font-bold mt-1 tracking-widest uppercase">Presupuesto de Servicios</p> <div style="text-align: right; font-size: 12px; color: #64748b; line-height: 1.6;">
<div id="pdf-company-name" style="font-size: 16px; font-weight: 900; color: #0f172a; margin-bottom: 4px;">Empresa S.L.</div>
<div id="pdf-company-dni">CIF: B12345678</div>
<div id="pdf-company-address">Calle Falsa 123</div>
<div id="pdf-company-location">28000 Madrid (Madrid)</div>
</div>
</div>
<div style="display: flex; justify-content: space-between; margin-bottom: 40px;">
<div>
<h1 style="font-size: 32px; font-weight: 900; color: #2563eb; margin: 0 0 10px 0; letter-spacing: -1px;">PRESUPUESTO</h1>
<div style="font-size: 14px; color: #64748b; line-height: 1.6;">
<strong>Referencia:</strong> <span id="pdf-budget-id">#PRE-000</span><br>
<strong>Fecha:</strong> <span id="pdf-date">01/01/2026</span><br>
</div> </div>
</div> </div>
<div class="text-right">
<p class="text-2xl font-black text-blue-600 tracking-widest" id="pdf-budget-id">#PRE-000</p> <div style="background-color: #f8fafc; border: 1px solid #e2e8f0; padding: 20px; border-radius: 12px; width: 300px;">
<p class="text-sm font-bold text-slate-500 mt-1" id="pdf-date">Fecha: 01/01/2026</p> <h3 style="margin: 0 0 10px 0; font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: #94a3b8; font-weight: 800;">Presupuestado a:</h3>
<p id="pdf-client-name" style="font-size: 16px; font-weight: 800; color: #0f172a; margin: 0 0 8px 0;">Nombre Cliente</p>
<p style="font-size: 13px; margin: 0; color: #475569; line-height: 1.6;">
<span id="pdf-client-phone">Teléfono</span><br>
<span id="pdf-client-address">Dirección</span>
</p>
</div> </div>
</div> </div>
<div class="mb-10 bg-slate-50 p-6 rounded-2xl border border-slate-100"> <table style="width: 100%; border-collapse: collapse; margin-bottom: 40px;">
<h3 class="text-xs font-black text-slate-400 uppercase tracking-widest mb-3">Datos del Cliente</h3>
<p class="font-black text-xl text-slate-800 mb-1" id="pdf-client-name">Nombre Cliente</p>
<p class="text-sm font-bold text-slate-600 mb-1"><i data-lucide="phone" class="w-3 h-3 inline mr-1"></i> <span id="pdf-client-phone">Teléfono</span></p>
<p class="text-sm font-bold text-slate-600"><i data-lucide="map-pin" class="w-3 h-3 inline mr-1"></i> <span id="pdf-client-address">Dirección</span></p>
</div>
<table class="w-full mb-10 text-left border-collapse">
<thead> <thead>
<tr class="border-b-2 border-slate-200 text-xs font-black uppercase tracking-widest text-slate-400"> <tr>
<th class="py-3 px-2 w-1/2">Concepto</th> <th style="background: #f1f5f9; color: #475569; font-weight: 800; text-transform: uppercase; font-size: 11px; padding: 12px 15px; text-align: left; border-bottom: 2px solid #cbd5e1; border-radius: 8px 0 0 0;">Concepto</th>
<th class="py-3 px-2 text-center">Cantidad</th> <th style="background: #f1f5f9; color: #475569; font-weight: 800; text-transform: uppercase; font-size: 11px; padding: 12px 15px; text-align: center; border-bottom: 2px solid #cbd5e1;">Cant.</th>
<th class="py-3 px-2 text-right">Precio Ud.</th> <th style="background: #f1f5f9; color: #475569; font-weight: 800; text-transform: uppercase; font-size: 11px; padding: 12px 15px; text-align: right; border-bottom: 2px solid #cbd5e1;">Precio Ud.</th>
<th class="py-3 px-2 text-right">Total</th> <th style="background: #f1f5f9; color: #475569; font-weight: 800; text-transform: uppercase; font-size: 11px; padding: 12px 15px; text-align: right; border-bottom: 2px solid #cbd5e1; border-radius: 0 8px 0 0;">Total</th>
</tr> </tr>
</thead> </thead>
<tbody id="pdf-items" class="text-sm font-bold text-slate-700 divide-y divide-slate-100"> <tbody id="pdf-items">
</tbody> </tbody>
</table> </table>
<div class="flex justify-end mb-10"> <div style="width: 320px; margin-left: auto; border: 1px solid #e2e8f0; border-radius: 12px; overflow: hidden; margin-bottom: 40px;">
<div class="w-1/2 bg-slate-50 p-6 rounded-2xl border border-slate-100"> <div style="display: flex; justify-content: space-between; padding: 12px 20px; font-size: 13px; border-bottom: 1px solid #f1f5f9; color: #475569;">
<div class="flex justify-between py-2"> <span style="font-weight: 600; text-transform: uppercase; letter-spacing: 1px;">Base Imponible</span>
<span class="font-bold text-slate-500 text-sm uppercase tracking-widest">Subtotal</span> <span id="pdf-subtotal" style="font-weight: 800; color: #0f172a;">0.00 €</span>
<span class="font-black text-slate-700" id="pdf-subtotal">0.00€</span> </div>
</div> <div style="display: flex; justify-content: space-between; padding: 12px 20px; font-size: 13px; border-bottom: 1px solid #f1f5f9; color: #475569;">
<div class="flex justify-between py-2 border-b border-slate-200"> <span style="font-weight: 600; text-transform: uppercase; letter-spacing: 1px;">IVA (21%)</span>
<span class="font-bold text-slate-500 text-sm uppercase tracking-widest">IVA (21%)</span> <span id="pdf-tax" style="font-weight: 800; color: #0f172a;">0.00 €</span>
<span class="font-black text-amber-600" id="pdf-tax">0.00€</span> </div>
</div> <div style="display: flex; justify-content: space-between; padding: 16px 20px; background: #2563eb; color: white;">
<div class="flex justify-between py-4 text-xl font-black text-slate-800"> <span style="font-weight: 900; font-size: 16px; letter-spacing: 1px;">TOTAL A PAGAR</span>
<span class="uppercase tracking-widest">TOTAL A PAGAR</span> <span id="pdf-total" style="font-weight: 900; font-size: 20px;">0.00 €</span>
<span id="pdf-total" class="text-emerald-600 text-2xl">0.00€</span>
</div>
</div> </div>
</div> </div>
<div class="absolute bottom-10 left-10 right-10"> <div style="position: absolute; bottom: 50px; left: 50px; right: 50px;">
<div id="pdf-bank-info" class="mb-4 p-4 bg-blue-50 text-blue-800 rounded-xl text-xs font-bold border border-blue-100 hidden"> <div id="pdf-bank-info" style="margin-bottom: 20px; padding: 20px; background-color: #f0fdf4; border-left: 4px solid #22c55e; border-radius: 0 8px 8px 0; font-size: 12px; color: #166534; display: none;">
Para confirmar el presupuesto, puede realizar una transferencia o bizum a la siguiente cuenta:<br> <strong>INFORMACIÓN DE PAGO</strong><br>
<span class="text-sm font-black tracking-widest mt-1 block" id="pdf-bank-account">ES00 0000 0000 0000 0000</span> Para confirmar el presupuesto, por favor realice una transferencia a la siguiente cuenta indicando el número de referencia:<br>
<span id="pdf-bank-account" style="font-size: 16px; font-weight: 900; letter-spacing: 2px; margin-top: 8px; display: inline-block;">ES00 0000 0000 0000 0000</span>
</div> </div>
<div class="pt-4 border-t border-slate-200 text-center text-xs font-bold text-slate-400"> <div id="pdf-obs-info" style="margin-bottom: 30px; padding: 20px; background-color: #fefce8; border-left: 4px solid #f59e0b; border-radius: 0 8px 8px 0; font-size: 11px; color: #713f12; display: none;">
Documento generado automáticamente por el sistema. Este documento tiene validez como presupuesto inicial. <strong>OBSERVACIONES Y CONDICIONES</strong><br>
<span id="pdf-obs-text"></span>
</div>
<div style="text-align: center; font-size: 10px; color: #94a3b8; border-top: 1px solid #e2e8f0; padding-top: 20px;">
Documento generado por IntegraRepara - Sistema de Gestión de Asistencias
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@@ -824,41 +840,74 @@
showToast("⏳ Generando PDF, espera unos segundos..."); showToast("⏳ Generando PDF, espera unos segundos...");
let companyName = "IntegraRepara"; // Valores por defecto
let companyLogo = null; let empNombre = "IntegraRepara";
let bankAccount = null; let empDni = "CIF/NIF no configurado";
let empAddress = "Dirección no configurada";
let empCity = "";
let empState = "";
let empZip = "";
let empLogo = null;
let empIban = null;
let empObs = null;
try { try {
const confRes = await fetch(`${API_URL}/config/company`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } }); const confRes = await fetch(`${API_URL}/config/company`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } });
const confData = await confRes.json(); const confData = await confRes.json();
if (confData.ok && confData.config) {
companyName = confData.config.full_name || companyName;
companyLogo = confData.config.company_logo;
bankAccount = confData.config.portal_settings ? confData.config.portal_settings.bank_account : null;
}
} catch(e) {}
document.getElementById('pdf-company-name').innerText = companyName; if (confData.ok && confData.config) {
const logoEl = document.getElementById('pdf-company-logo'); empLogo = confData.config.company_logo || null;
if (companyLogo) {
logoEl.src = companyLogo; if (confData.config.billing_settings) {
logoEl.classList.remove('hidden'); const bSet = confData.config.billing_settings;
empNombre = bSet.name || confData.config.full_name || empNombre;
empDni = bSet.dni ? `CIF/NIF: ${bSet.dni}` : empDni;
empAddress = bSet.address || empAddress;
empCity = bSet.city || "";
empState = bSet.state || "";
empZip = bSet.zip || "";
empIban = bSet.iban || null;
empObs = bSet.obs || null;
} else {
// Fallback
empNombre = confData.config.full_name || empNombre;
}
}
} catch(e) { console.error("Error al cargar facturación", e); }
// Inyectamos los datos en el diseño
document.getElementById('pdf-company-name').innerText = empNombre;
document.getElementById('pdf-company-dni').innerText = empDni;
document.getElementById('pdf-company-address').innerText = empAddress;
const locText = [empZip, empCity, empState ? `(${empState})` : ''].filter(Boolean).join(' ');
document.getElementById('pdf-company-location').innerText = locText;
const logoImg = document.getElementById('pdf-company-logo');
const logoTxt = document.getElementById('pdf-company-name-fallback');
if (empLogo) {
logoImg.src = empLogo;
logoImg.style.display = 'block';
logoTxt.style.display = 'none';
} else { } else {
logoEl.classList.add('hidden'); logoImg.style.display = 'none';
logoTxt.innerText = empNombre;
logoTxt.style.display = 'block';
} }
document.getElementById('pdf-budget-id').innerText = `#PRE-${budget.id}`; document.getElementById('pdf-budget-id').innerText = `#PRE-${budget.id}`;
document.getElementById('pdf-date').innerText = `Fecha: ${new Date(budget.created_at).toLocaleDateString('es-ES')}`; document.getElementById('pdf-date').innerText = new Date(budget.created_at).toLocaleDateString('es-ES');
document.getElementById('pdf-client-name').innerText = budget.client_name || "Cliente Sin Nombre"; document.getElementById('pdf-client-name').innerText = budget.client_name || "Cliente Sin Nombre";
document.getElementById('pdf-client-phone').innerText = budget.client_phone || "-"; document.getElementById('pdf-client-phone').innerText = budget.client_phone || "-";
document.getElementById('pdf-client-address').innerText = budget.client_address || "-"; document.getElementById('pdf-client-address').innerText = budget.client_address || "-";
const itemsHtml = (budget.items || []).map(item => ` const itemsHtml = (budget.items || []).map(item => `
<tr class="hover:bg-slate-50 transition-colors"> <tr>
<td class="py-4 px-2 border-b border-slate-50">${item.concept}</td> <td style="padding: 15px; border-bottom: 1px solid #e2e8f0; font-size: 13px; color: #334155;">${item.concept}</td>
<td class="py-4 px-2 border-b border-slate-50 text-center">${item.qty}</td> <td style="padding: 15px; border-bottom: 1px solid #e2e8f0; font-size: 13px; color: #334155; text-align: center;">${item.qty}</td>
<td class="py-4 px-2 border-b border-slate-50 text-right">${parseFloat(item.price).toFixed(2)} €</td> <td style="padding: 15px; border-bottom: 1px solid #e2e8f0; font-size: 13px; color: #334155; text-align: right;">${parseFloat(item.price).toFixed(2)} €</td>
<td class="py-4 px-2 border-b border-slate-50 text-right font-black">${(item.qty * item.price).toFixed(2)} €</td> <td style="padding: 15px; border-bottom: 1px solid #e2e8f0; font-size: 13px; font-weight: 700; color: #0f172a; text-align: right;">${(item.qty * item.price).toFixed(2)} €</td>
</tr> </tr>
`).join(''); `).join('');
document.getElementById('pdf-items').innerHTML = itemsHtml; document.getElementById('pdf-items').innerHTML = itemsHtml;
@@ -868,15 +917,22 @@
document.getElementById('pdf-total').innerText = parseFloat(budget.total).toFixed(2) + " €"; document.getElementById('pdf-total').innerText = parseFloat(budget.total).toFixed(2) + " €";
const bankContainer = document.getElementById('pdf-bank-info'); const bankContainer = document.getElementById('pdf-bank-info');
if (bankAccount) { if (empIban) {
document.getElementById('pdf-bank-account').innerText = bankAccount; document.getElementById('pdf-bank-account').innerText = empIban;
bankContainer.classList.remove('hidden'); bankContainer.style.display = 'block';
} else { } else {
bankContainer.classList.add('hidden'); bankContainer.style.display = 'none';
} }
lucide.createIcons(); const obsContainer = document.getElementById('pdf-obs-info');
if (empObs) {
document.getElementById('pdf-obs-text').innerHTML = empObs.replace(/\n/g, '<br>');
obsContainer.style.display = 'block';
} else {
obsContainer.style.display = 'none';
}
// Generar PDF
const wrapper = document.getElementById('pdf-wrapper'); const wrapper = document.getElementById('pdf-wrapper');
wrapper.classList.remove('hidden'); wrapper.classList.remove('hidden');
wrapper.style.position = 'absolute'; wrapper.style.position = 'absolute';