feat(design): add 16 new components + update 5 pages (ronda 2)

Bloqueantes POS: modal-pago, ticket-termico, banner-cliente, fkeys-footer, columnas-costo-margen
Componentes nuevos: calculadora-cambio, panel-deslizante, badge-cfdi, arbol-colapsable, tarjeta-metrica, grafica-barras, selector-periodo, etiqueta-codigo-barras
Estados: estado-vacio, banner-offline, modal-confirmacion
Páginas actualizadas: facturación, contabilidad, dashboard, configuración, reportes
This commit is contained in:
Lucy
2026-04-01 07:06:34 +00:00
parent 380698258a
commit ccd3962458
25 changed files with 7153 additions and 129 deletions

View File

@@ -804,6 +804,83 @@
color: var(--color-error);
}
/* Columnas Costo/Margen (solo visibles con permiso Admin/Owner) */
.cart-item__cost,
.cart-item__margin {
display: none;
font-family: var(--font-mono);
font-size: var(--text-caption);
text-align: right;
min-width: 56px;
flex-shrink: 0;
}
.cart-item__cost {
color: var(--color-text-muted);
}
.cart-item__margin {
font-weight: var(--font-weight-bold);
}
.cart-item__margin.margin-high { color: var(--color-success); }
.cart-item__margin.margin-mid { color: var(--color-warning); }
.cart-item__margin.margin-low { color: var(--color-error); }
/* When cost columns are visible */
body.show-cost-columns .cart-item__cost,
body.show-cost-columns .cart-item__margin {
display: block;
}
/* Margin footer summary */
.margin-summary {
display: none;
padding: var(--space-2) var(--space-5);
border-top: 1px dashed var(--color-border);
font-size: var(--text-caption);
color: var(--color-text-muted);
}
body.show-cost-columns .margin-summary {
display: flex;
justify-content: space-between;
}
.margin-summary__value {
font-family: var(--font-mono);
font-weight: var(--font-weight-bold);
}
/* Toggle button for cost columns */
.cost-toggle {
display: flex;
align-items: center;
gap: var(--space-2);
padding: var(--space-1) var(--space-3);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: transparent;
color: var(--color-text-muted);
font-size: 10px;
font-family: var(--font-body);
letter-spacing: var(--tracking-wide);
text-transform: uppercase;
cursor: pointer;
transition: var(--transition-fast);
}
.cost-toggle:hover {
border-color: var(--color-primary);
color: var(--color-text-accent);
}
.cost-toggle.active {
background: var(--color-primary-muted);
border-color: var(--color-primary);
color: var(--color-text-accent);
}
/* Cart footer (totals + payment) */
.cart-footer {
flex-shrink: 0;
@@ -1423,6 +1500,7 @@
<div class="cart-header">
<div class="cart-header__top">
<div class="cart-header__sale-id" id="saleId">Venta #1247</div>
<button class="cost-toggle" id="costToggle" title="Mostrar costo/margen (Admin)">💲 C/M</button>
<span class="cart-header__status">Activa</span>
</div>
<div class="customer-row">
@@ -1448,6 +1526,12 @@
<!-- Populated by JS -->
</div>
<!-- Margin Summary (visible when cost columns are on) -->
<div class="margin-summary" id="marginSummary">
<span>Margen promedio ponderado:</span>
<span class="margin-summary__value" id="avgMargin">--</span>
</div>
<!-- Cart Footer -->
<div class="cart-footer">
@@ -1608,20 +1692,20 @@
DATA — Product catalogue
------------------------------------------------------------------ */
const PRODUCTS = [
{ id: 1, name: 'Balatas Delanteras', oem: 'TRW-GDB1246', price: 485.00, stock: 12, category: 'frenos', cat_label: 'Frenos' },
{ id: 2, name: 'Disco de Freno Ventilado',oem: 'BREMBO-09A388X',price: 1290.00, stock: 4, category: 'frenos', cat_label: 'Frenos' },
{ id: 3, name: 'Cilindro de Rueda', oem: 'LPR-4502', price: 320.00, stock: 7, category: 'frenos', cat_label: 'Frenos' },
{ id: 4, name: 'Bujía Iridium NGK', oem: 'NGK-ILKAR7L11', price: 185.00, stock: 48, category: 'motor', cat_label: 'Motor' },
{ id: 5, name: 'Empaque de Culata', oem: 'VICTOR-R10154', price: 890.00, stock: 2, category: 'motor', cat_label: 'Motor' },
{ id: 6, name: 'Correa de Distribución', oem: 'GATES-T236', price: 650.00, stock: 9, category: 'motor', cat_label: 'Motor' },
{ id: 7, name: 'Filtro de Aire Fram', oem: 'FRAM-CA10755', price: 195.00, stock: 23, category: 'filtros', cat_label: 'Filtros' },
{ id: 8, name: 'Filtro de Aceite Bosch', oem: 'BOSCH-0986AF10',price: 145.00, stock: 31, category: 'filtros', cat_label: 'Filtros' },
{ id: 9, name: 'Aceite Mobil 5W-30 1L', oem: 'MOBIL-5W30-1L', price: 210.00, stock: 64, category: 'aceites', cat_label: 'Aceites' },
{ id: 10, name: 'Aceite Pennzoil 10W-40', oem: 'PZ-10W40-1L', price: 175.00, stock: 50, category: 'aceites', cat_label: 'Aceites' },
{ id: 11, name: 'Amortiguador Delantero', oem: 'KYB-339123', price: 1450.00, stock: 3, category: 'suspension', cat_label: 'Suspensión'},
{ id: 12, name: 'Rótula de Dirección', oem: 'MOOG-K9648', price: 560.00, stock: 6, category: 'suspension', cat_label: 'Suspensión'},
{ id: 13, name: 'Bobina de Encendido', oem: 'DELPHI-GN10570',price: 780.00, stock: 5, category: 'electrico', cat_label: 'Eléctrico' },
{ id: 14, name: 'Sensor de Oxígeno Denso', oem: 'DENSO-234-4127',price: 920.00, stock: 4, category: 'electrico', cat_label: 'Eléctrico' },
{ id: 1, name: 'Balatas Delanteras', oem: 'TRW-GDB1246', price: 485.00, cost: 290.00, stock: 12, category: 'frenos', cat_label: 'Frenos' },
{ id: 2, name: 'Disco de Freno Ventilado',oem: 'BREMBO-09A388X',price: 1290.00, cost: 820.00, stock: 4, category: 'frenos', cat_label: 'Frenos' },
{ id: 3, name: 'Cilindro de Rueda', oem: 'LPR-4502', price: 320.00, cost: 195.00, stock: 7, category: 'frenos', cat_label: 'Frenos' },
{ id: 4, name: 'Bujía Iridium NGK', oem: 'NGK-ILKAR7L11', price: 185.00, cost: 98.00, stock: 48, category: 'motor', cat_label: 'Motor' },
{ id: 5, name: 'Empaque de Culata', oem: 'VICTOR-R10154', price: 890.00, cost: 580.00, stock: 2, category: 'motor', cat_label: 'Motor' },
{ id: 6, name: 'Correa de Distribución', oem: 'GATES-T236', price: 650.00, cost: 390.00, stock: 9, category: 'motor', cat_label: 'Motor' },
{ id: 7, name: 'Filtro de Aire Fram', oem: 'FRAM-CA10755', price: 195.00, cost: 85.00, stock: 23, category: 'filtros', cat_label: 'Filtros' },
{ id: 8, name: 'Filtro de Aceite Bosch', oem: 'BOSCH-0986AF10',price: 145.00, cost: 68.00, stock: 31, category: 'filtros', cat_label: 'Filtros' },
{ id: 9, name: 'Aceite Mobil 5W-30 1L', oem: 'MOBIL-5W30-1L', price: 210.00, cost: 155.00, stock: 64, category: 'aceites', cat_label: 'Aceites' },
{ id: 10, name: 'Aceite Pennzoil 10W-40', oem: 'PZ-10W40-1L', price: 175.00, cost: 120.00, stock: 50, category: 'aceites', cat_label: 'Aceites' },
{ id: 11, name: 'Amortiguador Delantero', oem: 'KYB-339123', price: 1450.00, cost: 950.00, stock: 3, category: 'suspension', cat_label: 'Suspensión'},
{ id: 12, name: 'Rótula de Dirección', oem: 'MOOG-K9648', price: 560.00, cost: 320.00, stock: 6, category: 'suspension', cat_label: 'Suspensión'},
{ id: 13, name: 'Bobina de Encendido', oem: 'DELPHI-GN10570',price: 780.00, cost: 480.00, stock: 5, category: 'electrico', cat_label: 'Eléctrico' },
{ id: 14, name: 'Sensor de Oxígeno Denso', oem: 'DENSO-234-4127',price: 920.00, cost: 610.00, stock: 4, category: 'electrico', cat_label: 'Eléctrico' },
];
/* ------------------------------------------------------------------
@@ -1857,6 +1941,8 @@
const p = getProduct(item.productId);
if (!p) return '';
const lineTotal = p.price * item.qty;
const margin = p.cost ? ((p.price - p.cost) / p.price * 100) : 0;
const marginClass = margin > 30 ? 'margin-high' : margin > 15 ? 'margin-mid' : 'margin-low';
return `
<div class="cart-item" role="listitem" data-product-id="${p.id}">
<div class="cart-item__qty-ctrl">
@@ -1868,6 +1954,8 @@
<div class="cart-item__name" title="${p.name}">${p.name}</div>
<div class="cart-item__unit">${fmt(p.price)} c/u</div>
</div>
<div class="cart-item__cost">${p.cost ? fmt(p.cost) : '—'}</div>
<div class="cart-item__margin ${marginClass}">${margin.toFixed(1)}%</div>
<div class="cart-item__total">${fmt(lineTotal)}</div>
<button class="cart-item__remove" data-id="${p.id}" aria-label="Eliminar ${p.name} del carrito">✕</button>
</div>`;
@@ -1890,8 +1978,41 @@
// disable cobrar if cart is empty
$btnCobrar.disabled = state.cart.length === 0;
// update weighted average margin
updateAvgMargin();
}
function updateAvgMargin() {
const $avg = document.getElementById('avgMargin');
if (!$avg) return;
let totalRevenue = 0, totalCost = 0;
state.cart.forEach(item => {
const p = getProduct(item.productId);
if (p && p.cost) {
totalRevenue += p.price * item.qty;
totalCost += p.cost * item.qty;
}
});
if (totalRevenue > 0) {
const avg = ((totalRevenue - totalCost) / totalRevenue * 100);
$avg.textContent = avg.toFixed(1) + '%';
$avg.className = 'margin-summary__value ' +
(avg > 30 ? 'margin-high' : avg > 15 ? 'margin-mid' : 'margin-low');
$avg.style.color = avg > 30 ? 'var(--color-success)' : avg > 15 ? 'var(--color-warning)' : 'var(--color-error)';
} else {
$avg.textContent = '--';
}
}
/* ------------------------------------------------------------------
COST/MARGIN TOGGLE (Admin/Owner only)
------------------------------------------------------------------ */
document.getElementById('costToggle').addEventListener('click', function() {
document.body.classList.toggle('show-cost-columns');
this.classList.toggle('active');
});
/* ------------------------------------------------------------------
DISCOUNT INPUT
------------------------------------------------------------------ */