// factura-express.jsx - Link directo C09 para verificar factura sin login.
function FacturaExpressScreen({ facturaId, vendedoraId }) {
const T = window.T;
const { ProductTile } = window;
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState('');
const [data, setData] = React.useState(null);
const [mode, setMode] = React.useState('review');
const [nota, setNota] = React.useState('');
const [producto, setProducto] = React.useState({ codigo: '', nombre: '', cantidad: 1 });
const [submitting, setSubmitting] = React.useState(false);
const [pagoModal, setPagoModal] = React.useState(false);
const reload = React.useCallback(async () => {
setLoading(true);
setError('');
try {
const result = await window.pedidosApi.obtenerFacturaExpress({ facturaId, vendedoraId });
setData(result);
} catch (e) {
console.error('factura express load', e);
setError(e.message || 'No pude abrir la factura');
} finally {
setLoading(false);
}
}, [facturaId, vendedoraId]);
React.useEffect(() => { reload(); }, [reload]);
if (loading) {
return (
);
}
if (error || !data?.factura) {
return (
No pude abrir esta factura
{error || 'Pide a Inova que te envie el link nuevamente.'}
);
}
const factura = data.factura;
const vendedora = data.vendedora || { id: vendedoraId, nombre: 'Vendedora' };
const resolvedVendedoraId = vendedora?.id || vendedoraId;
const pagos = data.pagos || [];
const feedback = data.feedback || window.pedidosApi.latestFacturaFeedback?.(factura);
const productos = (factura.productosFinales && factura.productosFinales.length)
? factura.productosFinales
: (factura.productosOriginales || []);
const saldo = window.facturaSaldo ? window.facturaSaldo(factura, pagos) : Math.max(0, +factura.aPagar || 0);
const isProcesada = window.facturaEsCobrable ? window.facturaEsCobrable(factura) : factura.estado === 'procesada';
const resumenPagos = window.facturaPagosResumen
? window.facturaPagosResumen(factura, pagos)
: { montoVerificado: 0, montoPendiente: 0, saldoConPendientes: saldo };
const hasIssue = feedback && feedback.respuesta !== 'aceptada';
const accepted = feedback?.respuesta === 'aceptada';
const paymentPlan = window.getPaymentPlanForCampaign ? window.getPaymentPlanForCampaign(factura.campaignId) : null;
const paymentPlanLabel = paymentPlan?.label || factura.campaignId || 'esta campana';
async function submitFeedback(tipo) {
if (submitting) return;
setSubmitting(true);
setError('');
try {
const cleanProduct = {
codigo: String(producto.codigo || '').trim(),
nombre: String(producto.nombre || '').trim(),
cantidad: Math.max(1, parseInt(producto.cantidad, 10) || 1),
};
if (tipo === 'falta_producto' && !cleanProduct.codigo && !cleanProduct.nombre) {
setError('Indica al menos el codigo o el nombre del producto que falta.');
setSubmitting(false);
return;
}
const result = await window.pedidosApi.enviarFeedbackFacturaExpress({
facturaId: factura.id || facturaId,
vendedoraId: resolvedVendedoraId,
tipo,
nota,
producto: tipo === 'falta_producto' ? cleanProduct : null,
});
setData(prev => ({ ...prev, factura: result.factura, feedback: result.feedback }));
setMode('sent');
} catch (e) {
console.error('factura express feedback', e);
setError(e.message || 'No pude guardar tu respuesta');
} finally {
setSubmitting(false);
}
}
const feedbackLabel = {
aceptada: 'Factura aceptada',
falta_producto: 'Reporto producto faltante',
producto_sobra: 'Reporto producto de mas',
cambio_cantidad: 'Reporto cantidad incorrecta',
identidad_incorrecta: 'Reporto que esta factura no es suya',
}[feedback?.respuesta];
return (
Verificacion {factura.campaignId || ''}
Revisa tu factura
{vendedora.nombre}, confirma si estos son los productos correctos. Si falta algo o ves algo de mas, avisanos aqui.
Para esta campana no necesitas clave ni descargar la app. Usa este link para revisar tu factura.
{isProcesada ? 'Factura final' : 'En revision antes de cerrar'}
${(+factura.aPagar || 0).toFixed(2)}
A pagar a Inova · total pedido ${(+factura.total || 0).toFixed(2)}
Tu 20%
${(+factura.ganancia || 0).toFixed(2)}
{feedbackLabel && (
{feedbackLabel}
)}
{isProcesada && (resumenPagos.montoVerificado > 0.01 || resumenPagos.montoPendiente > 0.01 || saldo > 0.01) && (
)}
{window.PaymentPlanCard && (
)}
{isProcesada && (
setPagoModal(true)} disabled={saldo <= 0.01} style={primaryBtn(T, saldo <= 0.01)}>
{saldo > 0.01 ? `Registrar pago - saldo ${window.fmtMoney ? window.fmtMoney(saldo) : `$${saldo.toFixed(2)}`}` : 'Factura pagada'}
)}
Productos
{productos.map((p, i) => {
const unavailable = !!p.no_disponible;
return (
{p.codigo} · {p.catalogo || 'Catalogo'}
{p.nombre}
{p.tono && (
{p.tono}
)}
{unavailable && (
{p.motivo_no_disponible === 'recepcion_venezuela'
? 'No llego a Venezuela / no se cobra'
: 'Agotado / no se cobra'}
)}
x{p.cantidad}
${((+p.precio || 0) * (+p.cantidad || 0)).toFixed(2)}
);
})}
{!isProcesada && mode !== 'sent' && (
submitFeedback('aceptada')} disabled={submitting} style={primaryBtn(T, submitting)}>
Si, esta correcta
setMode(mode === 'missing' ? 'review' : 'missing')} style={secondaryBtn(T)}>
Me falta un producto
setMode(mode === 'extra' ? 'review' : 'extra')} style={secondaryBtn(T)}>
Hay un producto de mas o cantidad incorrecta
)}
{!isProcesada && mode === 'missing' && (
submitFeedback('falta_producto')}
/>
)}
{!isProcesada && mode === 'extra' && (
submitFeedback('producto_sobra')}
simple
/>
)}
{mode === 'sent' && (
Respuesta guardada. Inova la vera en el admin antes de cerrar la factura.
)}
{isProcesada && (
setPagoModal(true)} disabled={saldo <= 0.01} style={primaryBtn(T, saldo <= 0.01)}>
{saldo > 0.01 ? 'Registrar pago' : 'Factura pagada'}
setMode(mode === 'identity' ? 'review' : 'identity')} disabled={submitting} style={secondaryBtn(T)}>
Esta factura no es mia
)}
{isProcesada && mode === 'identity' && (
submitFeedback('identidad_incorrecta')}
simple
placeholder="Ej. este link no es mio / estos productos no son de mi pedido"
/>
)}
{error && (
)}
{pagoModal && (
setPagoModal(false)}
onSaved={() => { setPagoModal(false); reload(); }}
/>
)}
);
}
function FeedbackForm({ T, title, producto, setProducto, nota, setNota, submitting, onSubmit, simple, placeholder }) {
return (
);
}
function inputStyle(T) {
return {
width: '100%',
padding: '11px 12px',
borderRadius: 12,
border: `1px solid ${T.hairline}`,
background: T.paper,
fontFamily: T.sans,
fontSize: 13,
color: T.ink,
boxSizing: 'border-box',
outline: 'none',
};
}
function primaryBtn(T, disabled) {
return {
width: '100%',
padding: '15px 18px',
borderRadius: 16,
background: disabled ? T.inkMute : T.accent,
color: '#fff',
border: 'none',
cursor: disabled ? 'wait' : 'pointer',
fontFamily: T.sans,
fontSize: 14,
fontWeight: 700,
};
}
function secondaryBtn(T) {
return {
width: '100%',
padding: '13px 16px',
borderRadius: 16,
background: T.paperAlt,
color: T.ink,
border: `1px solid ${T.hairlineStrong || T.hairline}`,
cursor: 'pointer',
fontFamily: T.sans,
fontSize: 13,
fontWeight: 600,
};
}
function FacturaMini({ label, value, T }) {
return (
);
}
window.FacturaExpressScreen = FacturaExpressScreen;