diff --git a/contabilidad.html b/contabilidad.html index a8eb9f0..bf12234 100644 --- a/contabilidad.html +++ b/contabilidad.html @@ -848,6 +848,72 @@ const name = document.getElementById('bName').value; if(!name) return showToast("El nombre es obligatorio"); + const items = []; + document.querySelectorAll('#budgetLines > div').forEach(line => { + const idEl = line.querySelector('.b-item-id'); // Por si lograste poner el input oculto + const conceptEl = line.querySelector('.b-concept'); + const qtyEl = line.querySelector('.b-qty'); + const priceEl = line.querySelector('.b-price'); + + if (conceptEl && qtyEl && priceEl) { + const c = conceptEl.value; + // Forzamos que si escribes comas, se pasen a puntos para que JS no falle + const qStr = qtyEl.value.toString().replace(',', '.'); + const pStr = priceEl.value.toString().replace(',', '.'); + + const q = parseFloat(qStr) || 0; + const p = parseFloat(pStr) || 0; + + if(c && q > 0) { + const itemObj = { concept: c, qty: q, price: p }; + if (idEl && idEl.value) itemObj.id = parseInt(idEl.value); + items.push(itemObj); + } + } + }); + + if(items.length === 0) return showToast("Añade al menos un concepto"); + + // Aseguramos que limpiamos el símbolo de euro y cambiamos comas por puntos en los totales + const sub = parseFloat(document.getElementById('bSubtotal').innerText.replace('€', '').replace(',', '.')) || 0; + const tax = parseFloat(document.getElementById('bTax').innerText.replace('€', '').replace(',', '.')) || 0; + const tot = parseFloat(document.getElementById('bTotal').innerText.replace('€', '').replace(',', '.')) || 0; + + const payload = { client_phone: phone, client_name: name, client_address: document.getElementById('bAddress').value, items, subtotal: sub, tax, total: tot }; + + const editId = document.getElementById('editBudgetId').value; + + try { + let res; + if (editId) { + res = await fetch(`${API_URL}/budgets/${editId}`, { method: 'PUT', headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("token")}` }, body: JSON.stringify(payload) }); + } else { + res = await fetch(`${API_URL}/budgets`, { method: 'POST', headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("token")}` }, body: JSON.stringify(payload) }); + } + + // Leemos como texto por si el servidor devuelve un string vacío o error HTML + const textResponse = await res.text(); + let data = {}; + if (textResponse) { + try { data = JSON.parse(textResponse); } catch(e) { console.warn("El servidor no devolvió JSON puro:", textResponse); } + } + + if (res.ok && data.ok !== false) { + document.getElementById('budgetModal').classList.add('hidden'); + showToast(editId ? "✅ Presupuesto actualizado" : "✅ Presupuesto guardado"); + loadBudgets(); + } else { + showToast("❌ Error: " + (data.error || "Fallo en el servidor")); + console.error("Respuesta del servidor:", data, textResponse); + } + } catch (error) { + showToast("❌ Error de conexión al guardar."); + console.error("Error en fetch:", error); + } + } + const name = document.getElementById('bName').value; + if(!name) return showToast("El nombre es obligatorio"); + const items = []; document.querySelectorAll('#budgetLines > div').forEach(line => { const c = line.querySelector('.b-concept').value;