// Pagos screens — "Pagos" tab + Factura detail // Relies on window.loadBilling / saveBilling, facturaSaldo, facturaEstado, etc. const ESTADO_META = { 'por-pagar': { label: 'Por pagar', color: 'oklch(0.55 0.05 75)', bg: 'oklch(0.94 0.01 75)' }, 'pago-pendiente':{ label: 'Verificando', color: 'oklch(0.55 0.14 75)', bg: 'oklch(0.95 0.06 85)' }, 'abonada': { label: 'Abonada', color: 'oklch(0.52 0.14 155)', bg: 'oklch(0.94 0.06 155)' }, 'vencida': { label: 'Vencida', color: 'oklch(0.5 0.18 25)', bg: 'oklch(0.94 0.07 25)' }, 'pagada': { label: 'Pagada', color: 'oklch(0.48 0.14 155)', bg: 'oklch(0.94 0.06 155)' }, 'retirado': { label: 'Retirado', color: T_or('inkMute'), bg: T_or('paperAlt') }, }; function T_or(k) { return (window.T && window.T[k]) || '#888'; } function PagosTab({ vendedora, onOpenFactura }) { const T = window.T; const { Icon } = window; const billing = window.useBilling ? window.useBilling(vendedora?.id) : { state: window.loadBilling(), loading: false }; const state = billing.state; const facturas = state.facturas; const pagos = state.pagos; if (billing.loading && facturas.length === 0) { return (
Cargando facturas…
); } const deuda = window.totalDeuda(facturas, pagos); const vencida = window.totalDeudaVencida(facturas, pagos); const proximoPago = (() => { const upcoming = []; facturas.forEach(f => { const saldo = window.facturaSaldo(f, pagos); if (saldo <= 0.01) return; f.cuotas.forEach(c => { if (c.status !== 'pagada' && new Date(c.fecha) >= new Date()) upcoming.push({ fecha: c.fecha, monto: c.monto }); }); }); upcoming.sort((a, b) => new Date(a.fecha) - new Date(b.fecha)); return upcoming[0]; })(); const sortedFac = [...facturas].sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)); return (
{/* Header */}
Mis Facturas
Pagos
{/* Deuda hero */}
0 ? 'oklch(0.42 0.18 25)' : T.ink, color: '#fff', borderRadius: 24, padding: 24, position: 'relative', overflow: 'hidden', }}>
{deuda > 0 ? 'Debes' : 'Estás al día'}
${deuda.toFixed(2)}
{vencida > 0 && (
${vencida.toFixed(2)} vencido
)} {proximoPago && deuda > 0 && (
0 ? 8 : 14, fontFamily: T.sans, fontSize: 13, color: 'rgba(255,255,255,0.75)', }}> Próxima cuota {window.fmtDate(proximoPago.fecha)} · {window.fmtMoney(proximoPago.monto)}
)}
{/* Empresa contact */} {deuda > 0 && (
Datos para pagar
)} {/* Facturas list */}
{sortedFac.length === 0 ? (
Aún no tienes facturas.
Arma tu primer pedido.
) : sortedFac.map(f => { const saldo = window.facturaSaldo(f, pagos); const estado = window.facturaEstado(f, pagos); const meta = ESTADO_META[estado] || ESTADO_META['por-pagar']; const pct = Math.round((1 - Math.max(0, saldo) / f.aPagar) * 100); const camp = state.campaigns.find(c => c.id === f.campaignId); return ( ); })}
); } function InfoRow({ label, value }) { const T = window.T; return (
{label}
{value}
); } function CuotaDot({ cuota }) { const T = window.T; const isPagada = cuota.status === 'pagada'; const now = new Date(); const isVencida = !isPagada && new Date(cuota.fecha) < now; const bg = isPagada ? 'oklch(0.6 0.14 155)' : isVencida ? 'oklch(0.55 0.18 25)' : T.hairlineStrong; return (
{window.fmtDate(cuota.fecha)}
${cuota.monto.toFixed(2)}
); } // ——— Factura detail ——— function FacturaDetail({ factura, vendedora, onClose, onRegistrarPago }) { const T = window.T; const { Icon } = window; const billing = window.useBilling ? window.useBilling(vendedora?.id) : { state: window.loadBilling(), loading: false }; const state = billing.state; const pagos = state.pagos.filter(p => p.facturaId === factura.id); const saldo = window.facturaSaldo(factura, pagos); const estado = window.facturaEstado(factura, pagos); const meta = ESTADO_META[estado] || ESTADO_META['por-pagar']; const camp = state.campaigns.find(c => c.id === factura.campaignId); const pagoStatusColor = (s) => s === 'verificado' ? 'oklch(0.5 0.14 155)' : s === 'rechazado' ? 'oklch(0.55 0.18 25)' : 'oklch(0.55 0.14 75)'; return (
{/* Top bar */}
{camp?.nombre || factura.campaignId}
Factura {factura.id.slice(-5)}
{/* Hero saldo */}
0.01 ? (estado === 'vencida' ? 'oklch(0.42 0.18 25)' : T.ink) : 'oklch(0.45 0.14 155)', color: '#fff', borderRadius: 22, padding: 22, }}>
{meta.label}
{saldo > 0.01 ? 'Saldo pendiente' : 'Pagado completo'}
${Math.max(0, saldo).toFixed(2)}
{factura.retiroCodigo && (
Código de retiro
{factura.retiroCodigo}
)}
{/* Desglose */}
Desglose
{/* Cuotas */}
{factura.cuotas.map((c, i) => { const isPagada = c.status === 'pagada'; const isVencida = !isPagada && new Date(c.fecha) < new Date(); return (
{isPagada ? '✓' : i + 1}
{window.fmtMoney(c.monto)}
{new Date(c.fecha).toLocaleDateString('es', { weekday: 'short', day: 'numeric', month: 'long' })}
{isPagada ? 'Pagada' : isVencida ? 'Vencida' : 'Próxima'}
); })}
{/* Pagos registrados */} {pagos.length > 0 && (
{pagos.slice().sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)).map(p => (
{window.fmtMoney(p.monto)}
{p.status === 'verificado' ? '✓ Verificado' : p.status === 'rechazado' ? 'Rechazado' : 'Verificando…'}
{p.metodo}{p.banco ? ` · ${p.banco}` : ''}{p.referencia ? ` · Ref ${p.referencia}` : ''}
{window.fmtDate(p.fecha)} · {new Date(p.createdAt).toLocaleDateString('es', { day: '2-digit', month: 'short' })}
{p.rejectReason && (
Razón: {p.rejectReason}
)}
))}
)} {/* Register payment button */} {saldo > 0.01 && (
)}
); } function Row({ label, value, accent, bold }) { const T = window.T; return (
{label} {value}
); } Object.assign(window, { PagosTab, FacturaDetail });