Files
Autoparts-DB/pos/static/js/reports.min.js
consultoria-as 21959f1b37 FASE 7d: Lazy Loading + Minificación + Auto-serve minified
Cambios implementados:

1. Lazy loading de imágenes:
   - catalog.js: loading="lazy" decoding="async" en part cards y detail panel
   - inventory.js: lazy loading en imagen de detalle de item

2. Minificación de assets:
   - scripts/minify-assets.sh: minifica JS (terser) y CSS para POS y Dashboard
   - 25 archivos .min.js + 5 .min.css generados en pos/static/
   - 14 archivos .min.js + 8 .min.css generados en dashboard/

3. Nginx auto-serve minified:
   - try_files $1.min.js antes de servir .js original
   - try_files $1.min.css antes de servir .css original
   - Transparente para los templates HTML (cero cambios en HTML)

4. Cache warming script:
   - scripts/warm_vehicle_cache.py: pobla Redis con vehicle info por batches
   - Mitiga DISTINCT ON + 4 JOINs sobre 2B filas
   - Corre en background, procesa ~1.5M parts

Tests: 73/73 pasando
2026-04-27 08:34:24 +00:00

1 line
25 KiB
JavaScript

const Reports=(()=>{function t(){return localStorage.getItem("pos_token")||""}function a(t){return parseFloat(t||0).toLocaleString("es-MX",{minimumFractionDigits:2,maximumFractionDigits:2})}function e(t){return parseInt(t||0).toLocaleString("es-MX")}function n(t){if(!t)return"--";var a=new Date(t);return isNaN(a)?t:a.toLocaleDateString("es-MX",{day:"2-digit",month:"short",year:"numeric"})+" "+a.toLocaleTimeString("es-MX",{hour:"2-digit",minute:"2-digit"})}function r(t){return'<div style="text-align:center;padding:var(--space-6);color:var(--color-text-muted)">'+t+"</div>"}function o(t){return'<div style="text-align:center;padding:var(--space-6);color:var(--color-error)">'+t+"</div>"}var d={ventas:!1,inventario:!1,clientes:!1,financieros:!1};function l(t){document.documentElement.setAttribute("data-theme",t);try{localStorage.setItem("nexus-theme",t)}catch(t){}var a=document.getElementById("btn-industrial"),e=document.getElementById("btn-modern");a&&a.classList.toggle("is-active","industrial"===t),e&&e.classList.toggle("is-active","modern"===t)}function s(t,a){document.querySelectorAll(".tab-panel").forEach((function(t){t.classList.remove("is-active")})),document.querySelectorAll(".tab-btn").forEach((function(t){t.classList.remove("is-active")}));var e=document.getElementById("panel-"+t);e&&e.classList.add("is-active"),a&&a.classList.add("is-active"),d[t]||("ventas"===t?h():"inventario"===t?v():"clientes"===t?m():"financieros"===t&&p())}function i(){var t=document.getElementById("live-clock");if(t){var a=new Date,e=function(t){return String(t).padStart(2,"0")};t.textContent=e(a.getHours())+":"+e(a.getMinutes())+":"+e(a.getSeconds())}}async function c(a){var e=await fetch(a,{headers:{Authorization:`Bearer ${t()}`,"Content-Type":"application/json"}});if(!e.ok)throw new Error("HTTP "+e.status);return e.json()}function g(t,a,e){return'<div class="kpi-card"><div class="kpi-card__label">'+t+'</div><div class="kpi-card__value">'+a+"</div>"+(e?'<div class="kpi-card__sub">'+e+"</div>":"")+"</div>"}async function h(){d.ventas=!0;var t=document.getElementById("ventas-date-from").value,l=document.getElementById("ventas-date-to").value,s=new URLSearchParams;t&&s.set("date_from",t),l&&s.set("date_to",l),s.set("per_page","200");var i=document.getElementById("ventas-kpis"),h=document.getElementById("ventas-bar-chart"),v=document.getElementById("ventas-por-vendedor"),m=document.getElementById("ventas-por-metodo"),p=document.getElementById("ventas-detalle");i.innerHTML='<div style="text-align:center;padding:var(--space-6);color:var(--color-text-muted)">Cargando...</div>',h.innerHTML="",v.innerHTML='<div style="text-align:center;padding:var(--space-6);color:var(--color-text-muted)">Cargando...</div>',m.innerHTML='<div style="text-align:center;padding:var(--space-6);color:var(--color-text-muted)">Cargando...</div>',p.innerHTML='<div style="text-align:center;padding:var(--space-6);color:var(--color-text-muted)">Cargando...</div>';try{for(var u=[],y=1,b=1;y<=b;){s.set("page",y);var f=await c("/pos/api/sales?"+s.toString());if(u=u.concat(f.data||[]),b=f.pagination?f.pagination.total_pages:1,++y>50)break}var _=u.filter((function(t){return"completed"===t.status})),T=_.reduce((function(t,a){return t+a.total}),0),M=_.length,x=M>0?T/M:0;i.innerHTML=g("Total Ventas","$"+a(T),M+" transacciones")+g("Ticket Promedio","$"+a(x),"")+g("Transacciones",e(M),"")+g("Descuentos","$"+a(_.reduce((function(t,a){return t+a.discount_total}),0)),"");var L={},E=["Dom","Lun","Mar","Mie","Jue","Vie","Sab"];_.forEach((function(t){var a=t.created_at.substring(0,10);L[a]=(L[a]||0)+t.total}));var C=Object.keys(L).sort().slice(-7),w=Math.max.apply(null,C.map((function(t){return L[t]})))||1;if(C.length>0){var $='<div class="bar-chart-card__title">Ventas por Dia</div><div class="bar-chart">';C.forEach((function(t){var e=L[t],n=Math.round(e/w*100),r=E[new Date(t+"T12:00:00").getDay()],o=e>=1e3?"$"+(e/1e3).toFixed(1)+"k":"$"+a(e);$+='<div class="bar-chart__col"><div class="bar-chart__bar-wrap"><div class="bar-chart__bar" style="height:'+n+'%"><span class="bar-chart__bar-val">'+o+'</span></div></div><div class="bar-chart__day">'+r+"</div></div>"})),$+="</div>",h.innerHTML=$}var S={};_.forEach((function(t){var a=t.employee_id||0;S[a]||(S[a]={name:t.employee_name||"Sin asignar",count:0,total:0}),S[a].count++,S[a].total+=t.total}));var I=Object.values(S).sort((function(t,a){return a.total-t.total})),H='<div class="table-card__header"><span class="table-card__title">Ventas por Vendedor</span></div>';H+='<div class="table-wrap"><table class="data-table"><thead><tr><th>Vendedor</th><th class="align-right"># Ventas</th><th class="align-right">Total</th><th class="align-right">Ticket Prom.</th></tr></thead><tbody>',I.forEach((function(t){var e=t.name.split(" ").map((function(t){return t[0]})).join("").substring(0,2).toUpperCase();H+='<tr><td><div style="display:flex;align-items:center;gap:var(--space-2)"><div style="width:28px;height:28px;background:var(--color-primary);color:var(--color-text-inverse);display:flex;align-items:center;justify-content:center;font-size:0.65rem;font-weight:700;flex-shrink:0;border-radius:var(--radius-full)">'+e+'</div><span class="td-strong">'+t.name+'</span></div></td><td class="align-right td-mono">'+t.count+'</td><td class="align-right td-mono-accent">$'+a(t.total)+'</td><td class="align-right td-mono">$'+a(t.count>0?t.total/t.count:0)+"</td></tr>"})),H+="</tbody></table></div>",v.innerHTML=I.length?H:r("Sin datos de vendedores");var k={};_.forEach((function(t){var a=t.payment_method||"Otro";k[a]=(k[a]||0)+t.total}));var B=Object.entries(k).sort((function(t,a){return a[1]-t[1]})),A=(B.length>0&&B[0][1],{cash:"Efectivo",card:"Tarjeta",transfer:"Transferencia",credit:"Credito",mixed:"Mixto"}),D=["","pay-method__bar--b","pay-method__bar--c","pay-method__bar--d"],P='<div class="table-card__header"><span class="table-card__title">Ventas por Metodo de Pago</span></div>';P+='<div class="table-wrap" style="padding:var(--space-4) var(--space-5)">',B.forEach((function(t,e){var n=T>0?Math.round(t[1]/T*100):0,r=A[t[0]]||t[0];P+='<div class="pay-method-row"><span class="pay-method__label">'+r+'</span><div class="pay-method__bar-wrap"><div class="pay-method__bar '+(D[e]||"")+'" style="width:'+n+'%"></div></div><span class="pay-method__val">$'+a(t[1])+' <span style="color:var(--color-text-muted);font-weight:400">'+n+"%</span></span></div>"})),P+="</div>",m.innerHTML=B.length?P:r("Sin datos de metodos");var V='<div class="table-card__header"><span class="table-card__title">Detalle de Ventas</span><span class="pill pill--muted">'+u.length+" registros</span></div>";V+='<div class="table-wrap"><table class="data-table"><thead><tr><th>#</th><th>Fecha</th><th>Vendedor</th><th>Cliente</th><th>Pago</th><th class="align-right">Subtotal</th><th class="align-right">Desc.</th><th class="align-right">IVA</th><th class="align-right">Total</th><th>Estado</th></tr></thead><tbody>',u.slice(0,100).forEach((function(t){var e="completed"===t.status?"pill--success":"cancelled"===t.status?"pill--error":"pill--warning",r="completed"===t.status?"Completada":"cancelled"===t.status?"Cancelada":t.status;V+='<tr><td class="td-mono">'+t.id+"</td><td>"+n(t.created_at)+"</td><td>"+(t.employee_name||"--")+"</td><td>"+(t.customer_name||"Mostrador")+"</td><td>"+(A[t.payment_method]||t.payment_method||"--")+'</td><td class="align-right td-mono">$'+a(t.subtotal)+'</td><td class="align-right td-mono">$'+a(t.discount_total)+'</td><td class="align-right td-mono">$'+a(t.tax_total)+'</td><td class="align-right td-mono-accent">$'+a(t.total)+'</td><td><span class="pill '+e+'">'+r+"</span></td></tr>"})),V+="</tbody></table></div>",p.innerHTML=V}catch(t){i.innerHTML=o("Error cargando ventas: "+t.message),v.innerHTML="",m.innerHTML="",p.innerHTML=""}}async function v(){d.inventario=!0;var t=document.getElementById("inventario-kpis"),n=document.getElementById("inventario-valorizacion"),l=document.getElementById("inventario-abc"),s=document.getElementById("inventario-low-stock"),i=document.getElementById("inventario-no-movement");t.innerHTML='<div style="text-align:center;padding:var(--space-6);color:var(--color-text-muted)">Cargando...</div>',n.innerHTML='<div style="text-align:center;padding:var(--space-6);color:var(--color-text-muted)">Cargando...</div>',l.innerHTML='<div style="text-align:center;padding:var(--space-6);color:var(--color-text-muted)">Cargando...</div>',s.innerHTML='<div style="text-align:center;padding:var(--space-6);color:var(--color-text-muted)">Cargando...</div>',i.innerHTML='<div style="text-align:center;padding:var(--space-6);color:var(--color-text-muted)">Cargando...</div>';try{var[h,v,m,p]=await Promise.all([c("/pos/api/inventory/reports/valuation"),c("/pos/api/inventory/reports/abc"),c("/pos/api/inventory/reports/low-stock"),c("/pos/api/inventory/reports/no-movement")]);t.innerHTML=g("Valor Total Inventario","$"+a(h.grand_total),e(h.item_count)+" SKUs activos")+g("Clasificacion A",e(v.summary.A)+" SKUs","80% del volumen de ventas")+g("Stock Bajo",e(m.count)+" productos","debajo del minimo")+g("Sin Movimiento",e(p.count)+" productos",">"+p.days_threshold+" dias");var u=(h.data||[]).slice(0,20),y='<div class="table-card__header"><span class="table-card__title">Inventario Valorizado</span><span class="pill pill--muted">Top 20 de '+e(h.item_count)+"</span></div>";y+='<div class="table-wrap"><table class="data-table"><thead><tr><th>Producto</th><th>No. Parte</th><th>Marca</th><th class="align-right">Stock</th><th class="align-right">Costo Unit.</th><th class="align-right">Valor</th></tr></thead><tbody>',u.forEach((function(t){y+='<tr><td class="td-strong">'+t.name+'</td><td class="td-mono" style="color:var(--color-text-muted)">'+(t.part_number||"--")+"</td><td>"+(t.brand||"--")+'</td><td class="align-right td-mono">'+e(t.stock)+'</td><td class="align-right td-mono">$'+a(t.cost)+'</td><td class="align-right td-mono-accent">$'+a(t.value)+"</td></tr>"})),y+="</tbody></table></div>",n.innerHTML=y;var b=(v.data||[]).slice(0,30),f='<div class="table-card__header"><span class="table-card__title">Clasificacion ABC de Inventario</span><span class="pill pill--success">A: '+v.summary.A+'</span> <span class="pill pill--warning">B: '+v.summary.B+'</span> <span class="pill pill--muted">C: '+v.summary.C+"</span></div>";f+='<div class="table-wrap"><table class="data-table"><thead><tr><th>Producto</th><th>No. Parte</th><th>Marca</th><th class="align-right">Vol. Ventas</th><th class="align-right">% Acum.</th><th class="align-center">Clase</th></tr></thead><tbody>',b.forEach((function(t){var a="A"===t.classification?"pill--success":"B"===t.classification?"pill--warning":"pill--muted";f+='<tr><td class="td-strong">'+t.name+'</td><td class="td-mono" style="color:var(--color-text-muted)">'+(t.part_number||"--")+"</td><td>"+(t.brand||"--")+'</td><td class="align-right td-mono">'+e(t.sales_volume)+'</td><td class="align-right td-mono">'+t.cumulative_pct+'%</td><td class="align-center"><span class="pill '+a+'">'+t.classification+"</span></td></tr>"})),f+="</tbody></table></div>",l.innerHTML=f;var _=m.data||[],T='<div class="table-card__header"><span class="table-card__title">Productos con Stock Bajo</span><span class="pill pill--warning pill--dot">'+m.count+" productos</span></div>";T+='<div class="table-wrap"><table class="data-table"><thead><tr><th>Producto</th><th>No. Parte</th><th>Marca</th><th class="align-right">Stock</th><th class="align-right">Minimo</th><th class="align-right">Deficit</th></tr></thead><tbody>',_.slice(0,30).forEach((function(t){var a=t.stock<=0||t.stock<t.min_stock/2?"color:var(--color-error)":"color:var(--color-warning)";T+='<tr><td class="td-strong">'+t.name+'</td><td class="td-mono" style="color:var(--color-text-muted)">'+(t.part_number||"--")+"</td><td>"+(t.brand||"--")+'</td><td class="align-right td-mono" style="'+a+'">'+e(t.stock)+'</td><td class="align-right td-mono">'+e(t.min_stock)+'</td><td class="align-right td-mono-accent">'+e(t.deficit)+"</td></tr>"})),T+="</tbody></table></div>",s.innerHTML=_.length?T:r("No hay productos con stock bajo");var M=p.data||[],x='<div class="table-card__header"><span class="table-card__title">Productos Sin Movimiento (>'+p.days_threshold+' dias)</span><span class="pill pill--muted">'+p.count+" SKUs</span></div>";x+='<div class="table-wrap"><table class="data-table"><thead><tr><th>Producto</th><th>No. Parte</th><th>Marca</th><th class="align-right">Stock</th><th class="align-right">Costo Unit.</th><th>Ultimo Movimiento</th></tr></thead><tbody>',M.slice(0,30).forEach((function(t){x+='<tr><td class="td-strong">'+t.name+'</td><td class="td-mono" style="color:var(--color-text-muted)">'+(t.part_number||"--")+"</td><td>"+(t.brand||"--")+'</td><td class="align-right td-mono">'+e(t.stock)+'</td><td class="align-right td-mono">$'+a(t.cost)+'</td><td style="color:var(--color-text-muted)">'+function(t){if(!t)return"--";var a=new Date(t);return isNaN(a)?t:a.toLocaleDateString("es-MX",{day:"2-digit",month:"short",year:"numeric"})}(t.last_movement)+"</td></tr>"})),x+="</tbody></table></div>",i.innerHTML=M.length?x:r("No hay productos sin movimiento")}catch(a){t.innerHTML=o("Error cargando inventario: "+a.message),n.innerHTML="",l.innerHTML="",s.innerHTML="",i.innerHTML=""}}async function m(){d.clientes=!0;var t=document.getElementById("clientes-kpis"),n=document.getElementById("clientes-aging");t.innerHTML='<div style="text-align:center;padding:var(--space-6);color:var(--color-text-muted)">Cargando...</div>',n.innerHTML='<div style="text-align:center;padding:var(--space-6);color:var(--color-text-muted)">Cargando...</div>';try{var l=await c("/pos/api/accounting/aging"),s=l.data||[],i=l.totals||{};t.innerHTML=g("Clientes con Credito",e(s.length),"con saldo pendiente")+g("Saldo Total","$"+a(i.total),"")+g("Corriente","$"+a(i.corriente),"no vencido")+g("Vencido >90 dias","$"+a(i.d90_plus),i.d90_plus>0?'<span class="kpi-card__delta kpi-card__delta--down">requiere atencion</span>':"");var h='<div class="table-card__header"><span class="table-card__title">Antiguedad de Saldos</span><span class="pill pill--error pill--dot">'+s.length+" clientes</span></div>";h+='<div class="table-wrap"><table class="data-table"><thead><tr><th>Cliente</th><th>RFC</th><th class="align-right">Corriente</th><th class="align-right">1-30 dias</th><th class="align-right">31-60 dias</th><th class="align-right">61-90 dias</th><th class="align-right">90+ dias</th><th class="align-right">Total</th></tr></thead><tbody>',s.forEach((function(t){h+='<tr><td class="td-strong">'+t.name+'</td><td class="td-mono" style="color:var(--color-text-muted)">'+(t.rfc||"--")+'</td><td class="align-right td-mono">$'+a(t.corriente)+'</td><td class="align-right td-mono">$'+a(t.d1_30)+'</td><td class="align-right td-mono"'+(t.d31_60>0?' style="color:var(--color-warning)"':"")+">$"+a(t.d31_60)+'</td><td class="align-right td-mono"'+(t.d61_90>0?' style="color:var(--color-error)"':"")+">$"+a(t.d61_90)+'</td><td class="align-right td-mono"'+(t.d90_plus>0?' style="color:var(--color-error);font-weight:700"':"")+">$"+a(t.d90_plus)+'</td><td class="align-right td-mono-accent">$'+a(t.total)+"</td></tr>"})),h+='<tr style="background:var(--color-surface-2);font-weight:700"><td colspan="2">TOTAL</td><td class="align-right td-mono">$'+a(i.corriente)+'</td><td class="align-right td-mono">$'+a(i.d1_30)+'</td><td class="align-right td-mono">$'+a(i.d31_60)+'</td><td class="align-right td-mono">$'+a(i.d61_90)+'</td><td class="align-right td-mono">$'+a(i.d90_plus)+'</td><td class="align-right td-mono-accent">$'+a(i.total)+"</td></tr>",h+="</tbody></table></div>",n.innerHTML=s.length?h:r("No hay saldos pendientes de credito")}catch(a){t.innerHTML=o("Error cargando datos de clientes: "+a.message),n.innerHTML=""}}async function p(){d.financieros=!0;var t=document.getElementById("fin-month"),e=document.getElementById("fin-year"),l=parseInt(e.value),s=parseInt(t.value),i=document.getElementById("financieros-kpis"),h=document.getElementById("financieros-income"),v=document.getElementById("financieros-balance"),m=document.getElementById("financieros-trial"),p=document.getElementById("financieros-cortes");i.innerHTML='<div style="text-align:center;padding:var(--space-6);color:var(--color-text-muted)">Cargando...</div>',h.innerHTML='<div style="text-align:center;padding:var(--space-6);color:var(--color-text-muted)">Cargando...</div>',v.innerHTML='<div style="text-align:center;padding:var(--space-6);color:var(--color-text-muted)">Cargando...</div>',m.innerHTML='<div style="text-align:center;padding:var(--space-6);color:var(--color-text-muted)">Cargando...</div>',p.innerHTML='<div style="text-align:center;padding:var(--space-6);color:var(--color-text-muted)">Cargando...</div>';try{var[u,y,b,f]=await Promise.all([c("/pos/api/accounting/income-statement?year="+l+"&month="+s),c("/pos/api/accounting/balance-sheet"),c("/pos/api/accounting/trial-balance?year="+l+"&month="+s),c("/pos/api/register/history?per_page=50")]);i.innerHTML=g("Ingresos","$"+a(u.ingresos.total),"periodo "+s+"/"+l)+g("Costos","$"+a(u.costos.total),"")+g("Utilidad Bruta","$"+a(u.utilidad_bruta),"")+g("Utilidad Neta","$"+a(u.utilidad_neta),u.ingresos.total>0?"Margen: "+(u.utilidad_neta/u.ingresos.total*100).toFixed(1)+"%":"");var _='<div class="table-card__header"><span class="table-card__title">Estado de Resultados</span><span class="pill pill--muted">'+s+"/"+l+"</span></div>";_+='<div class="table-wrap"><table class="data-table"><thead><tr><th>Cuenta</th><th>Codigo</th><th class="align-right">Monto</th></tr></thead><tbody>',_+='<tr style="background:var(--color-surface-2)"><td colspan="2" class="td-strong">INGRESOS</td><td></td></tr>',(u.ingresos.items||[]).forEach((function(t){_+='<tr><td style="padding-left:var(--space-6)">'+t.name+'</td><td class="td-mono" style="color:var(--color-text-muted)">'+t.code+'</td><td class="align-right td-mono">$'+a(t.amount)+"</td></tr>"})),_+='<tr style="font-weight:700"><td style="padding-left:var(--space-6)">Total Ingresos</td><td></td><td class="align-right td-mono-accent">$'+a(u.ingresos.total)+"</td></tr>",_+='<tr style="background:var(--color-surface-2)"><td colspan="2" class="td-strong">COSTOS</td><td></td></tr>',(u.costos.items||[]).forEach((function(t){_+='<tr><td style="padding-left:var(--space-6)">'+t.name+'</td><td class="td-mono" style="color:var(--color-text-muted)">'+t.code+'</td><td class="align-right td-mono">$'+a(t.amount)+"</td></tr>"})),_+='<tr style="font-weight:700"><td style="padding-left:var(--space-6)">Total Costos</td><td></td><td class="align-right td-mono">$'+a(u.costos.total)+"</td></tr>",_+='<tr style="background:var(--color-primary-muted);font-weight:700"><td>UTILIDAD BRUTA</td><td></td><td class="align-right td-mono-accent">$'+a(u.utilidad_bruta)+"</td></tr>",_+='<tr style="background:var(--color-surface-2)"><td colspan="2" class="td-strong">GASTOS</td><td></td></tr>',(u.gastos.items||[]).forEach((function(t){_+='<tr><td style="padding-left:var(--space-6)">'+t.name+'</td><td class="td-mono" style="color:var(--color-text-muted)">'+t.code+'</td><td class="align-right td-mono">$'+a(t.amount)+"</td></tr>"})),_+='<tr style="font-weight:700"><td style="padding-left:var(--space-6)">Total Gastos</td><td></td><td class="align-right td-mono">$'+a(u.gastos.total)+"</td></tr>";var T=u.utilidad_neta>=0?"var(--color-success)":"var(--color-error)";_+='<tr style="background:var(--color-primary-muted);font-weight:700"><td>UTILIDAD NETA</td><td></td><td class="align-right" style="font-family:var(--font-mono);color:'+T+'">$'+a(u.utilidad_neta)+"</td></tr>",_+="</tbody></table></div>",h.innerHTML=_;var M='<div class="table-card__header"><span class="table-card__title">Balance General</span><span class="pill '+(y.balanced?"pill--success":"pill--error")+'">'+(y.balanced?"Cuadrado":"Descuadrado")+"</span></div>";M+='<div class="table-wrap"><table class="data-table"><thead><tr><th>Cuenta</th><th>Codigo</th><th class="align-right">Saldo</th></tr></thead><tbody>',M+='<tr style="background:var(--color-surface-2)"><td colspan="2" class="td-strong">ACTIVO</td><td></td></tr>',(y.activo.items||[]).forEach((function(t){M+='<tr><td style="padding-left:var(--space-6)">'+t.name+'</td><td class="td-mono" style="color:var(--color-text-muted)">'+t.code+'</td><td class="align-right td-mono">$'+a(t.balance)+"</td></tr>"})),M+='<tr style="font-weight:700"><td>Total Activo</td><td></td><td class="align-right td-mono-accent">$'+a(y.activo.total)+"</td></tr>",M+='<tr style="background:var(--color-surface-2)"><td colspan="2" class="td-strong">PASIVO</td><td></td></tr>',(y.pasivo.items||[]).forEach((function(t){M+='<tr><td style="padding-left:var(--space-6)">'+t.name+'</td><td class="td-mono" style="color:var(--color-text-muted)">'+t.code+'</td><td class="align-right td-mono">$'+a(t.balance)+"</td></tr>"})),M+='<tr style="font-weight:700"><td>Total Pasivo</td><td></td><td class="align-right td-mono">$'+a(y.pasivo.total)+"</td></tr>",M+='<tr style="background:var(--color-surface-2)"><td colspan="2" class="td-strong">CAPITAL</td><td></td></tr>',(y.capital.items||[]).forEach((function(t){M+='<tr><td style="padding-left:var(--space-6)">'+t.name+'</td><td class="td-mono" style="color:var(--color-text-muted)">'+t.code+'</td><td class="align-right td-mono">$'+a(t.balance)+"</td></tr>"})),M+='<tr style="font-weight:700"><td>Total Capital</td><td></td><td class="align-right td-mono">$'+a(y.capital.total)+"</td></tr>",M+='<tr style="background:var(--color-primary-muted);font-weight:700"><td>Pasivo + Capital</td><td></td><td class="align-right td-mono-accent">$'+a(y.pasivo.total+y.capital.total)+"</td></tr>",M+="</tbody></table></div>",v.innerHTML=M;var x=b.data||[],L='<div class="table-card__header"><span class="table-card__title">Balanza de Comprobacion</span><span class="pill pill--muted">'+s+"/"+l+"</span></div>";L+='<div class="table-wrap"><table class="data-table"><thead><tr><th>Codigo</th><th>Cuenta</th><th>Tipo</th><th class="align-right">Saldo Inicial</th><th class="align-right">Cargos</th><th class="align-right">Abonos</th><th class="align-right">Saldo Final</th></tr></thead><tbody>',x.forEach((function(t){L+='<tr><td class="td-mono">'+t.code+'</td><td class="td-strong">'+t.name+'</td><td><span class="pill pill--muted">'+t.type+'</span></td><td class="align-right td-mono">$'+a(t.saldo_inicial)+'</td><td class="align-right td-mono">$'+a(t.cargos)+'</td><td class="align-right td-mono">$'+a(t.abonos)+'</td><td class="align-right td-mono-accent">$'+a(t.saldo_final)+"</td></tr>"})),L+="</tbody></table></div>",m.innerHTML=x.length?L:r("Sin movimientos contables en este periodo");var E=f.data||[],C='<div class="table-card__header"><span class="table-card__title">Cortes de Caja</span><span class="pill pill--muted">'+(f.pagination?f.pagination.total:E.length)+" cortes</span></div>";C+='<div class="table-wrap"><table class="data-table"><thead><tr><th>Caja</th><th>Empleado</th><th>Apertura</th><th>Cierre</th><th class="align-right">Monto Apertura</th><th class="align-right">Esperado</th><th class="align-right">Cierre Real</th><th class="align-right">Diferencia</th></tr></thead><tbody>',E.forEach((function(t){var e=t.difference<0?"color:var(--color-error)":t.difference>0?"color:var(--color-warning)":"color:var(--color-success)";C+='<tr><td class="td-mono">#'+t.register_number+'</td><td class="td-strong">'+(t.employee_name||"--")+'</td><td style="color:var(--color-text-muted)">'+n(t.opened_at)+'</td><td style="color:var(--color-text-muted)">'+n(t.closed_at)+'</td><td class="align-right td-mono">$'+a(t.opening_amount)+'</td><td class="align-right td-mono">$'+a(t.expected_amount)+'</td><td class="align-right td-mono">$'+a(t.closing_amount)+'</td><td class="align-right td-mono" style="'+e+'">$'+a(t.difference)+"</td></tr>"})),C+="</tbody></table></div>",p.innerHTML=E.length?C:r("No hay cortes de caja registrados")}catch(t){i.innerHTML=o("Error cargando reportes financieros: "+t.message),h.innerHTML="",v.innerHTML="",m.innerHTML="",p.innerHTML=""}}function u(){if(t()||(window.location.href="/pos/login",0)){try{l(localStorage.getItem("nexus-theme")||"industrial")}catch(t){}i(),setInterval(i,1e3);var a=new Date,e=new Date(a.getFullYear(),a.getMonth(),1),n=document.getElementById("ventas-date-from"),r=document.getElementById("ventas-date-to");n&&(n.value=e.toISOString().substring(0,10)),r&&(r.value=a.toISOString().substring(0,10));var o=document.getElementById("fin-month"),d=document.getElementById("fin-year");if(o)for(var s=["Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre"],c=0;c<12;c++){(v=document.createElement("option")).value=c+1,v.textContent=s[c],c===a.getMonth()&&(v.selected=!0),o.appendChild(v)}if(d)for(var g=a.getFullYear();g>=a.getFullYear()-3;g--){var v;(v=document.createElement("option")).value=g,v.textContent=g,d.appendChild(v)}h()}}return window.setTheme=l,window.switchTab=s,document.addEventListener("DOMContentLoaded",u),{init:u,setTheme:l,switchTab:s,loadVentas:h,loadInventario:v,loadClientes:m,loadFinancieros:p,fmt:a}})();function exportReportCSV(){for(var t=document.querySelectorAll("table"),a=null,e=0;e<t.length;e++){var n=t[e];if(null!==n.offsetParent&&n.querySelector("tbody tr")){a=n;break}}if(a){var r=[],o=a.querySelectorAll("thead th");if(o.length&&r.push(Array.from(o).map((function(t){return'"'+t.textContent.trim().replace(/"/g,'""')+'"'})).join(",")),a.querySelectorAll("tbody tr").forEach((function(t){var a=t.querySelectorAll("td");r.push(Array.from(a).map((function(t){return'"'+t.textContent.trim().replace(/"/g,'""')+'"'})).join(","))})),r.length<=1)alert("La tabla esta vacia.");else{var d=r.join("\n"),l=new Blob(["\ufeff"+d],{type:"text/csv;charset=utf-8;"}),s=URL.createObjectURL(l),i=document.createElement("a");i.href=s,i.download="reporte_nexus_"+(new Date).toISOString().slice(0,10)+".csv",i.click(),URL.revokeObjectURL(s)}}else alert("No hay tabla de datos para exportar en esta vista.")}