const DEFAULT_BRAND = { name: 'Acme Estudio', initials: 'A', color: '#1f3a5f', tint: '#eef2f7', rfc: 'ACM850101AA1', address: 'Av. Reforma 222, CDMX · acme.studio', }; const DEFAULT_DATA = { numero: '0123', fecha: '7 jun 2026', validez: '22 jun 2026', cliente: 'Globex Corporation', clienteRfc: 'GLO910215QX3', moneda: 'USD', iva: true, items: [ { desc: 'Diseño e implementación de API REST', qty: 1, price: 3200 }, { desc: 'Integración con pasarela de pago', qty: 1, price: 1400 }, { desc: 'Soporte y mantenimiento (mensual)', qty: 3, price: 400 }, ], notas: 'Validez de la oferta: 15 días. Precios en USD, no incluyen retenciones. 50% anticipo, 50% contra entrega.', }; function fmtMoney(n, moneda) { const s = n.toLocaleString('es-MX', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); return `$${s} ${moneda}`; } function totals(data) { const subtotal = data.items.reduce((a, it) => a + it.qty * it.price, 0); const iva = data.iva ? subtotal * 0.16 : 0; return { subtotal, iva, total: subtotal + iva }; } function Row({ k, v, muted }) { return (
{k} {v}
); } function CotizacionDoc({ data = DEFAULT_DATA, brand = DEFAULT_BRAND }) { const t = totals(data); const ink = '#1a2430'; const muted = '#5d6b7a'; return (
{/* Header */}
{brand.initials}
{brand.name}
{brand.address}
COTIZACIÓN
N.º {data.numero}
{/* Meta */}
Para
{data.cliente}
RFC {data.clienteRfc}
{[['Fecha', data.fecha], ['Válida hasta', data.validez], ['Moneda', data.moneda]].map(([k, v]) => (
{k}{v}
))}
{/* Items */}
DescripciónCantP. UnitImporte
{data.items.map((it, i) => (
{it.desc} {it.qty} {it.price.toLocaleString('es-MX', { minimumFractionDigits: 2 })} {(it.qty * it.price).toLocaleString('es-MX', { minimumFractionDigits: 2 })}
))} {/* Totals */}
{data.iva && }
Total {fmtMoney(t.total, data.moneda)}
{/* Notes */}
Condiciones
{data.notas}
{/* Footer */}
{brand.name} · RFC {brand.rfc}
{brand.address}
Firma autorizada
1 / 1
); } window.TectoCorp = { CotizacionDoc, fmtMoney, totals, DEFAULT_BRAND, DEFAULT_DATA };