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
1 line
25 KiB
JavaScript
1 line
25 KiB
JavaScript
!function(){"use strict";var t="/pos/api/inventory",e=localStorage.getItem("pos_token");if(e){var o={Authorization:"Bearer "+e,"Content-Type":"application/json"},n=1,a="",r=null,i=window.switchTab;window.switchTab=function(t){"function"==typeof i&&i(t),"alertas"===t&&v(),"stock"===t&&m(n)};var s,d=document.getElementById("productSearch");d&&d.addEventListener("input",(function(){clearTimeout(s),s=setTimeout((function(){m(1,d.value.trim())}),350)})),window._loadItems=function(t){m(t)},window.loadItems=function(t,e){m(t,e)},window.viewHistory=function(e){c(t+"/items/"+e+"/history").then((function(t){if(t){var e=t.data||[],o="";e.length?(o='<table class="data-table"><thead><tr><th>Fecha</th><th>Tipo</th><th>Cantidad</th><th>Costo</th><th>Empleado</th><th>Notas</th></tr></thead><tbody>',e.forEach((function(t){var e=t.quantity>0?"var(--color-success)":"var(--color-error)";o+='<tr><td style="font-size:var(--text-caption);">'+u(t.date)+"</td><td>"+u(t.type)+'</td><td style="color:'+e+';font-weight:600;">'+(t.quantity>0?"+":"")+t.quantity+'</td><td class="td--amount">'+(t.cost?"$"+l(t.cost):"—")+"</td><td>"+u(t.employee)+'</td><td style="font-size:var(--text-caption);">'+u(t.notes)+"</td></tr>"})),o+="</tbody></table>"):o='<p style="color:var(--color-text-muted);text-align:center;padding:var(--space-4);">Sin movimientos</p>',document.getElementById("historyContent").innerHTML=o,document.getElementById("historyModal").classList.add("is-open")}}))},window.viewProductDetail=g,window.uploadItemImage=function(o){var n=document.createElement("input");n.type="file",n.accept="image/jpeg,image/png,image/webp",n.onchange=function(){if(n.files&&n.files[0]){var a=n.files[0];if(a.size>5242880)alert("Imagen demasiado grande (max 5 MB)");else{var r=new FormData;r.append("file",a);var i=document.getElementById("imgUploadStatus");i&&(i.textContent="Subiendo..."),fetch(t+"/items/"+o+"/image",{method:"POST",headers:{Authorization:"Bearer "+e},body:r}).then((function(t){return t.json()})).then((function(t){t.image_url?g(o):i&&(i.textContent=t.error||"Error")})).catch((function(){i&&(i.textContent="Error de red")}))}}},n.click()},window.deleteItemImage=function(o){confirm("Eliminar imagen de este producto?")&&fetch(t+"/items/"+o+"/image",{method:"DELETE",headers:{Authorization:"Bearer "+e}}).then((function(t){return t.json()})).then((function(t){t.message?g(o):alert(t.error||"Error")})).catch((function(){alert("Error de red")}))},window.closeHistoryModal=function(){document.getElementById("historyModal").classList.remove("is-open")},window.showCreateModal=function(){document.getElementById("createModal").classList.add("is-open");var e=document.getElementById("newPartNumber");e&&!e._classifyBound&&(e._classifyBound=!0,e.addEventListener("blur",(function(){var e=this.value.trim();if(!(e.length<3)){var o,n,a=document.getElementById("newName");if(!a||!a.value.trim())o=e,(n=document.getElementById("createResult")).innerHTML='<span style="color:var(--color-text-muted);">Consultando IA...</span>',c(t+"/classify/"+encodeURIComponent(o)).then((function(t){if(t){t.name&&(document.getElementById("newName").value=t.name),t.brand&&(document.getElementById("newBrand").value=t.brand);var e=[];t.name&&e.push(t.name),t.brand&&e.push(t.brand),t.vehicle&&e.push(t.vehicle),t.category&&e.push(t.category),e.length>0?n.innerHTML='<span style="color:var(--color-accent);font-size:var(--text-caption);">Sugerido por IA: '+u(e.join(" | "))+"</span>":n.innerHTML='<span style="color:var(--color-text-muted);font-size:var(--text-caption);">IA no pudo identificar este numero de parte</span>'}})).catch((function(){n.innerHTML=""}))}})))},window.closeCreateModal=function(){document.getElementById("createModal").classList.remove("is-open"),document.getElementById("createResult").innerHTML=""},window.createItem=function(){var e={part_number:document.getElementById("newPartNumber").value.trim(),name:document.getElementById("newName").value.trim(),brand:document.getElementById("newBrand").value.trim(),barcode:document.getElementById("newBarcode").value.trim()||void 0,cost:parseFloat(document.getElementById("newCost").value)||0,price_1:parseFloat(document.getElementById("newPrice1").value)||0,price_2:parseFloat(document.getElementById("newPrice2").value)||0,price_3:parseFloat(document.getElementById("newPrice3").value)||0,min_stock:parseInt(document.getElementById("newMinStock").value)||0,initial_stock:parseInt(document.getElementById("newInitialStock").value)||0,location:document.getElementById("newLocation").value.trim()};e.part_number&&e.name?c(t+"/items",{method:"POST",body:JSON.stringify(e)}).then((function(t){t&&t.id?(document.getElementById("createResult").innerHTML='<span style="color:var(--color-success);">Creado ID '+t.id+" | Barcode: "+t.barcode+"</span>",m(n)):document.getElementById("createResult").innerHTML='<span style="color:var(--color-error);">'+(t?t.error||"Error":"Error de red")+"</span>"})):document.getElementById("createResult").innerHTML='<span style="color:var(--color-error);">Numero de parte y nombre son obligatorios</span>'},window.showPurchaseModal=function(){document.getElementById("purchaseModal").classList.add("is-open")},window.closePurchaseModal=function(){document.getElementById("purchaseModal").classList.remove("is-open"),document.getElementById("purchaseResult").innerHTML=""},window.recordPurchase=function(){var e={inventory_id:parseInt(document.getElementById("purchaseItemId").value),quantity:parseInt(document.getElementById("purchaseQty").value),unit_cost:parseFloat(document.getElementById("purchaseCost").value),supplier_invoice:document.getElementById("purchaseInvoice").value.trim(),notes:document.getElementById("purchaseNotes").value.trim()};e.inventory_id&&e.quantity&&e.unit_cost?c(t+"/purchase",{method:"POST",body:JSON.stringify(e)}).then((function(t){document.getElementById("purchaseResult").innerHTML=t&&t.operation_id?'<span style="color:var(--color-success);">Compra registrada (op #'+t.operation_id+")</span>":'<span style="color:var(--color-error);">'+(t?t.error||"Error":"Error de red")+"</span>"})):document.getElementById("purchaseResult").innerHTML='<span style="color:var(--color-error);">Complete todos los campos obligatorios</span>'},window.showAdjustmentModal=function(){document.getElementById("adjustmentModal").classList.add("is-open")},window.closeAdjustmentModal=function(){document.getElementById("adjustmentModal").classList.remove("is-open"),document.getElementById("adjustResult").innerHTML=""},window.recordAdjustment=function(){var e={inventory_id:parseInt(document.getElementById("adjustItemId").value),quantity:parseInt(document.getElementById("adjustQty").value),reason:document.getElementById("adjustReason").value.trim()};e.inventory_id&&void 0!==e.quantity&&e.reason?c(t+"/adjustment",{method:"POST",body:JSON.stringify(e)}).then((function(t){document.getElementById("adjustResult").innerHTML=t&&t.operation_id?'<span style="color:var(--color-success);">Ajuste registrado (op #'+t.operation_id+")</span>":'<span style="color:var(--color-error);">'+(t?t.error||"Error":"Error de red")+"</span>"})):document.getElementById("adjustResult").innerHTML='<span style="color:var(--color-error);">Complete todos los campos (razon obligatoria)</span>'},window.showTransferModal=function(){document.getElementById("transferModal").classList.add("is-open")},window.closeTransferModal=function(){document.getElementById("transferModal").classList.remove("is-open"),document.getElementById("transferResult").innerHTML=""},window.recordTransfer=function(){var e={inventory_id:parseInt(document.getElementById("transferItemId").value),from_branch_id:parseInt(document.getElementById("transferFrom").value),to_branch_id:parseInt(document.getElementById("transferTo").value),quantity:parseInt(document.getElementById("transferQty").value),notes:document.getElementById("transferNotes").value.trim()};e.inventory_id&&e.from_branch_id&&e.to_branch_id&&e.quantity?c(t+"/transfer",{method:"POST",body:JSON.stringify(e)}).then((function(t){document.getElementById("transferResult").innerHTML=t&&t.out_operation_id?'<span style="color:var(--color-success);">Transferencia registrada</span>':'<span style="color:var(--color-error);">'+(t?t.error||"Error":"Error de red")+"</span>"})):document.getElementById("transferResult").innerHTML='<span style="color:var(--color-error);">Complete todos los campos</span>'},window.showCountModal=function(){document.getElementById("countModal").classList.add("is-open"),document.querySelectorAll("#countLines .count-row").length||p()},window.closeCountModal=function(){document.getElementById("countModal").classList.remove("is-open")},window.addCountLine=p,window.startPhysicalCount=function(){var e=document.querySelectorAll("#countLines .count-row"),o=[];e.forEach((function(t){var e=parseInt(t.querySelector(".count-inv-id").value),n=parseInt(t.querySelector(".count-qty").value);e&&!isNaN(n)&&o.push({inventory_id:e,counted_quantity:n})})),o.length?c(t+"/physical-count/start",{method:"POST",body:JSON.stringify({items:o})}).then((function(t){if(t&&t.count_id){r=t.count_id;var e='<h4 style="margin-bottom:var(--space-3);">Borrador #'+t.count_id+" — "+u(t.message)+"</h4>";e+='<table class="data-table"><thead><tr><th>ID</th><th>Esperado</th><th>Contado</th><th>Diferencia</th></tr></thead><tbody>',(t.results||[]).forEach((function(t){var o=0===t.difference?"var(--color-success)":t.difference<0?"var(--color-error)":"var(--color-warning)";e+="<tr><td>"+t.inventory_id+"</td><td>"+t.expected+"</td><td>"+t.counted+'</td><td style="color:'+o+';font-weight:600;">'+(t.difference>0?"+":"")+t.difference+"</td></tr>"})),e+="</tbody></table>",e+='<div style="margin-top:var(--space-3);display:flex;gap:var(--space-2);">',e+='<button class="btn btn--primary btn--sm" onclick="approvePhysicalCount()">Aprobar y aplicar ajustes</button>',e+='<button class="btn btn--ghost btn--sm" onclick="cancelDraft()">Cancelar borrador</button>',e+="</div>",document.getElementById("countResults").innerHTML=e}else document.getElementById("countResults").innerHTML='<span style="color:var(--color-error);">'+(t?t.error||"Error":"Error de red")+"</span>"})):alert("Agregue al menos una linea")},window.approvePhysicalCount=function(){r?c(t+"/physical-count/approve",{method:"POST",body:JSON.stringify({count_id:r})}).then((function(t){t&&"approved"===t.status?(document.getElementById("countResults").innerHTML='<span style="color:var(--color-success);">'+u(t.message)+"</span>",r=null):document.getElementById("countResults").innerHTML+='<br><span style="color:var(--color-error);">'+(t?t.error||"Error":"Error de red")+"</span>"})):alert("No hay borrador activo")},window.cancelDraft=function(){r=null,document.getElementById("countResults").innerHTML='<span style="color:var(--color-text-muted);">Borrador cancelado</span>'},window.loadAlerts=v,window.printBarcode=function(t,e,o){var n=window.open("","_blank","width=400,height=250");n.document.write("<html><head><title>Etiqueta</title><style>body{font-family:monospace;text-align:center;padding:20px;}h1{font-size:1.5rem;margin:8px 0;}p{margin:4px 0;}</style></head><body>"),n.document.write("<h1>"+t+"</h1>"),n.document.write("<p>"+e+"</p>"),n.document.write('<p style="font-size:0.85rem;">'+o+"</p>"),n.document.write("</body></html>"),n.document.close(),n.print()},m(1)}else window.location.href="/pos/login";function c(t,e){return fetch(t,Object.assign({headers:o},e||{})).then((function(t){return 401===t.status?(localStorage.removeItem("pos_token"),window.location.href="/pos/login",null):t.json()}))}function l(t){return(parseFloat(t)||0).toFixed(2)}function u(t){if(!t)return"";var e=document.createElement("div");return e.textContent=t,e.innerHTML}function m(e,o){n=e||1,a=void 0!==o?o:a;var r=new URLSearchParams({page:n,per_page:50});a&&r.set("q",a),c(t+"/items?"+r.toString()).then((function(t){if(t){var e=document.getElementById("productTableBody"),o=t.data||[];if(!o.length)return e.innerHTML='<tr><td colspan="11" style="text-align:center;padding:30px;color:var(--color-text-muted);">Sin productos</td></tr>',void(document.getElementById("productPagination").innerHTML="");e.innerHTML=o.map((function(t){return'<tr style="cursor:pointer;" onclick="viewProductDetail('+t.id+')"><td class="td--mono">'+u(t.barcode)+'</td><td class="td--mono">'+u(t.part_number)+'</td><td class="td--primary">'+u(t.name)+"</td><td>"+u(t.brand)+'</td><td style="text-align:right" class="td--primary">'+t.stock+'</td><td style="text-align:right" class="td--amount">$'+l(t.cost)+'</td><td style="text-align:right" class="td--amount">$'+l(t.price_1)+'</td><td style="text-align:right" class="td--amount">$'+l(t.price_2)+'</td><td style="text-align:right" class="td--amount">$'+l(t.price_3)+"</td><td>"+u(t.location)+'</td><td><button class="btn btn--ghost btn--sm" onclick="event.stopPropagation();viewHistory('+t.id+')">Historial</button> <button class="btn btn--ghost btn--sm" onclick="event.stopPropagation();printBarcode(\''+u(t.barcode)+"','"+u(t.part_number)+"','"+u(t.name)+"')\">Etiqueta</button></td></tr>"})).join("");var n=t.pagination||{},a=document.getElementById("productPagination");n.total_pages>1?a.innerHTML='<div class="pagination"><button class="page-btn" '+(n.page<=1?"disabled":'onclick="window._loadItems('+(n.page-1)+')"')+'>‹</button><span style="padding:0 var(--space-2);font-size:var(--text-body-sm);color:var(--color-text-muted);">'+n.page+" / "+n.total_pages+" ("+n.total+' productos)</span><button class="page-btn" '+(n.page>=n.total_pages?"disabled":'onclick="window._loadItems('+(n.page+1)+')"')+">›</button></div>":a.innerHTML='<span style="font-size:var(--text-body-sm);color:var(--color-text-muted);">'+(n.total||0)+" productos</span>"}}))}function p(){var t=document.getElementById("countLines"),e=document.createElement("div");e.className="count-row",e.innerHTML='<input type="number" placeholder="ID producto" class="count-inv-id" style="width:140px;" /><input type="number" placeholder="Cantidad contada" class="count-qty" style="width:160px;" /><button class="btn btn--ghost btn--sm" onclick="this.parentElement.remove()">Quitar</button>',t.appendChild(e)}function v(){c(t+"/alerts").then((function(t){if(t){var e=t.data||[],o=document.getElementById("alertsContent");if(o)if(e.length){var n="",a=e.filter((function(t){return"critical"===t.severity})),r=e.filter((function(t){return"warning"===t.severity})),i=e.filter((function(t){return"critical"!==t.severity&&"warning"!==t.severity}));a.length&&(n+='<div class="section-heading"><span class="section-heading__title">Criticas</span><div class="section-heading__line"></div><span class="badge badge--low">'+a.length+"</span></div>",n+='<div class="alerts-grid" style="margin-bottom:var(--space-6);">',a.forEach((function(t){var e="zero"===t.type?"AGOTADO":"low"===t.type?"BAJO":t.type.toUpperCase();n+=y(t,e,"critical")})),n+="</div>"),r.length&&(n+='<div class="section-heading"><span class="section-heading__title">Advertencias</span><div class="section-heading__line"></div><span class="badge badge--over">'+r.length+"</span></div>",n+='<div class="alerts-grid" style="margin-bottom:var(--space-6);">',r.forEach((function(t){n+=y(t,"EXCESO","warning")})),n+="</div>"),i.length&&(n+='<div class="section-heading"><span class="section-heading__title">Informativas</span><div class="section-heading__line"></div><span class="badge badge--ok">'+i.length+"</span></div>",n+='<div class="alerts-grid" style="margin-bottom:var(--space-6);">',i.forEach((function(t){n+=y(t,"INFO","info")})),n+="</div>"),o.innerHTML=n}else o.innerHTML='<p style="padding:var(--space-6);text-align:center;color:var(--color-text-muted);">Sin alertas activas</p>'}}))}function y(t,e,o){return'<div class="alert-card '+("critical"===o?"alert-card--critical":"warning"===o?"alert-card--warning":"alert-card--info")+'"><div class="alert-card__icon"><svg viewBox="0 0 24 24"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg></div><div class="alert-card__body"><div class="alert-card__title">['+e+"] "+u(t.part_number)+" — "+u(t.name)+'</div><div class="alert-card__desc">Stock: '+t.stock+(t.min_stock?" (min: "+t.min_stock+")":"")+(t.max_stock?" (max: "+t.max_stock+")":"")+" · Sucursal "+t.branch_id+"</div></div></div>"}function g(o){c(t+"/items/"+o).then((function(t){if(t&&!t.error){var n=t.history||[],a="";a+='<div style="text-align:center;margin-bottom:16px;padding-bottom:16px;border-bottom:1px solid var(--color-border);">',t.image_url?(a+='<img src="'+u(t.image_url)+"?t="+Date.now()+'" alt="'+u(t.name)+'" loading="lazy" decoding="async" style="max-width:100%;max-height:220px;object-fit:contain;border-radius:var(--radius-sm);margin-bottom:8px;display:block;margin-left:auto;margin-right:auto;">',a+='<div style="display:flex;gap:8px;justify-content:center;">',a+='<button class="btn btn--ghost btn--sm" onclick="uploadItemImage('+t.id+')">Cambiar imagen</button>',a+='<button class="btn btn--ghost btn--sm" style="color:var(--color-error);" onclick="deleteItemImage('+t.id+')">Eliminar imagen</button>',a+="</div>"):(a+='<div style="padding:24px;color:var(--color-text-muted);">',a+='<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" style="opacity:0.4;"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="M21 15l-5-5L5 21"/></svg>',a+='<div style="margin-top:8px;">Sin imagen</div>',a+="</div>",a+='<button class="btn btn--primary btn--sm" onclick="uploadItemImage('+t.id+')">Subir imagen</button>'),a+='<span id="imgUploadStatus" style="display:block;margin-top:4px;font-size:var(--text-caption);color:var(--color-text-muted);"></span>',a+="</div>",a+='<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:16px;padding-bottom:16px;border-bottom:1px solid var(--color-border);">',a+='<div><span style="font-size:var(--text-caption);color:var(--color-text-muted);text-transform:uppercase;display:block;">No. Parte</span><strong>'+u(t.part_number)+"</strong></div>",a+='<div><span style="font-size:var(--text-caption);color:var(--color-text-muted);text-transform:uppercase;display:block;">Nombre</span><strong>'+u(t.name)+"</strong></div>",a+='<div><span style="font-size:var(--text-caption);color:var(--color-text-muted);text-transform:uppercase;display:block;">Marca</span>'+u(t.brand)+"</div>",a+='<div><span style="font-size:var(--text-caption);color:var(--color-text-muted);text-transform:uppercase;display:block;">Codigo de Barras</span><span style="font-family:var(--font-mono);">'+u(t.barcode)+"</span></div>",a+='<div><span style="font-size:var(--text-caption);color:var(--color-text-muted);text-transform:uppercase;display:block;">Ubicacion</span>'+u(t.location||"-")+"</div>",a+='<div><span style="font-size:var(--text-caption);color:var(--color-text-muted);text-transform:uppercase;display:block;">Stock</span><strong style="font-size:1.2em;">'+(t.stock||0)+"</strong></div>",a+="</div>",a+='<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:16px;padding-bottom:16px;border-bottom:1px solid var(--color-border);">',a+='<div><span style="font-size:var(--text-caption);color:var(--color-text-muted);text-transform:uppercase;display:block;">Costo</span><span class="td--amount">$'+l(t.cost)+"</span></div>",a+='<div><span style="font-size:var(--text-caption);color:var(--color-text-muted);text-transform:uppercase;display:block;">Precio 1</span><span class="td--amount">$'+l(t.price_1)+"</span></div>",a+='<div><span style="font-size:var(--text-caption);color:var(--color-text-muted);text-transform:uppercase;display:block;">Precio 2</span><span class="td--amount">$'+l(t.price_2)+"</span></div>",a+='<div><span style="font-size:var(--text-caption);color:var(--color-text-muted);text-transform:uppercase;display:block;">Precio 3</span><span class="td--amount">$'+l(t.price_3)+"</span></div>",a+="</div>",a+='<div style="font-size:var(--text-caption);color:var(--color-text-muted);text-transform:uppercase;letter-spacing:var(--tracking-widest);margin-bottom:8px;">Cross-References / Equivalencias</div>',a+='<div id="crossRefContent" style="margin-bottom:16px;padding-bottom:16px;border-bottom:1px solid var(--color-border);">',a+='<p style="color:var(--color-text-muted);font-size:var(--text-caption);">Cargando equivalencias...</p>',a+="</div>";var r,i=t.part_number,s=t.catalog_part_id;r=s?"/pos/api/catalog/part/"+s:"/pos/api/catalog/search?q="+encodeURIComponent(i),fetch(r,{headers:{Authorization:"Bearer "+e}}).then((function(t){return t.json()})).then((function(t){var o=document.getElementById("crossRefContent");if(o){var n=t.alternatives||[],a=t.bodegas||[];!s&&t.data&&t.data.length>0?fetch("/pos/api/catalog/part/"+t.data[0].id_part,{headers:{Authorization:"Bearer "+e}}).then((function(t){return t.json()})).then((function(t){d(o,t.alternatives||[],t.bodegas||[])})).catch((function(){o.innerHTML='<p style="color:var(--color-text-muted);font-size:var(--text-caption);">Sin conexion al catalogo.</p>'})):d(o,n,a)}})).catch((function(){var t=document.getElementById("crossRefContent");t&&(t.innerHTML='<p style="color:var(--color-text-muted);font-size:var(--text-caption);">Sin conexion al catalogo central.</p>')})),a+='<div style="font-size:var(--text-caption);color:var(--color-text-muted);text-transform:uppercase;letter-spacing:var(--tracking-widest);margin-bottom:8px;">Vehiculos Compatibles</div>',a+='<div id="compatContent" style="margin-bottom:16px;padding-bottom:16px;border-bottom:1px solid var(--color-border);">',a+='<p style="color:var(--color-text-muted);font-size:var(--text-caption);">Cargando compatibilidades...</p>',a+="</div>",fetch("/pos/api/inventory/items/"+o+"/vehicles",{headers:{Authorization:"Bearer "+e}}).then((function(t){return t.json()})).then((function(t){var e=document.getElementById("compatContent");if(e){var n=t.vehicles||[],a="";n.length>0?(a+='<table class="data-table"><thead><tr><th>Marca</th><th>Modelo</th><th>Ano</th><th>Motor</th><th>Origen</th><th></th></tr></thead><tbody>',n.forEach((function(t){a+="<tr><td>"+u(t.brand||"")+"</td><td>"+u(t.model||"")+"</td><td>"+u(t.year||"")+"</td><td>"+u(t.engine||"")+"</td><td>"+u(t.source||"")+"</td>",a+='<td><button class="btn btn--ghost btn--sm" style="color:var(--color-error);" onclick="removeCompat('+o+","+t.model_year_engine_id+')">Quitar</button></td></tr>'})),a+="</tbody></table>"):a+='<p style="color:var(--color-text-muted);font-size:var(--text-caption);">Sin vehiculos vinculados.</p>',a+='<div style="margin-top:8px;"><button class="btn btn--primary btn--sm" onclick="autoMatchCompat('+o+')">Auto-Match por TecDoc</button> <span style="font-size:var(--text-caption);color:var(--color-text-muted);">Busca en catalogo central y vincula automaticamente</span></div>',e.innerHTML=a}})).catch((function(){var t=document.getElementById("compatContent");t&&(t.innerHTML='<p style="color:var(--color-text-muted);font-size:var(--text-caption);">Error al cargar compatibilidades.</p>')})),a+='<div style="font-size:var(--text-caption);color:var(--color-text-muted);text-transform:uppercase;letter-spacing:var(--tracking-widest);margin-bottom:8px;">Historial de Movimientos</div>',n.length?(a+='<table class="data-table"><thead><tr><th>Fecha</th><th>Tipo</th><th>Cantidad</th><th>Costo</th><th>Empleado</th><th>Notas</th></tr></thead><tbody>',n.forEach((function(t){var e=t.quantity>0?"var(--color-success)":"var(--color-error)";a+='<tr><td style="font-size:var(--text-caption);">'+u(t.date)+"</td><td>"+u(t.type)+'</td><td style="color:'+e+';font-weight:600;">'+(t.quantity>0?"+":"")+t.quantity+'</td><td class="td--amount">'+(t.cost?"$"+l(t.cost):"—")+"</td><td>"+u(t.employee)+'</td><td style="font-size:var(--text-caption);">'+u(t.notes)+"</td></tr>"})),a+="</tbody></table>"):a+='<p style="color:var(--color-text-muted);text-align:center;padding:var(--space-4);">Sin movimientos</p>',document.getElementById("historyContent").innerHTML=a,document.getElementById("historyModal").classList.add("is-open")}else alert(t?t.error:"Error de red");function d(t,e,o){var n="";o&&o.length>0&&(n+='<div style="margin-bottom:12px;"><strong style="font-size:var(--text-body-sm);color:var(--color-text-primary);">Disponible en Bodegas:</strong></div>',n+='<table class="data-table"><thead><tr><th>Bodega</th><th>Stock</th><th>Precio</th><th>Ubicacion</th></tr></thead><tbody>',o.forEach((function(t){n+="<tr><td>"+u(t.business_name||t.bodega||"")+"</td><td>"+(t.stock||t.stock_quantity||0)+'</td><td class="td--amount">$'+l(t.price||0)+"</td><td>"+u(t.location||t.warehouse_location||"")+"</td></tr>"})),n+="</tbody></table>"),e&&e.length>0&&(n+='<div style="margin-top:12px;margin-bottom:8px;"><strong style="font-size:var(--text-body-sm);color:var(--color-text-primary);">Partes Equivalentes (Aftermarket):</strong></div>',n+='<table class="data-table"><thead><tr><th>No. Parte</th><th>Fabricante</th><th>Nombre</th></tr></thead><tbody>',e.forEach((function(t){n+='<tr><td class="td--mono">'+u(t.part_number||t.cross_reference_number||"")+"</td><td>"+u(t.manufacturer||t.source_ref||"")+"</td><td>"+u(t.name||t.name_aftermarket_parts||"")+"</td></tr>"})),n+="</tbody></table>"),n||(n='<p style="color:var(--color-text-muted);font-size:var(--text-caption);">No se encontraron equivalencias para esta parte.</p>'),t.innerHTML=n}}))}}(); |