En el admin, cada método de pago tiene un campo Comisión con su porcentaje. El portal
lo recibe del API en cada carga (use-payment-methods.ts)… y ahí muere: ningún
componente lo muestra, ninguna pantalla lo suma, ningún servicio lo cobra. Del otro lado,
Stripe sí cobra el suyo: el fee real queda registrado en Transaction.feeAmount
con el neto en netAmount — escritos en cada pago, leídos por nadie.
Resultado: la plataforma sabe exactamente cuánto pierde por cobrar con tarjeta, y lo
pierde igual.
Método de pago · Stripe
admin · hoyEl 3% está configurado desde la migración de v1. Se guarda, se lista, se ordena por él en la tabla… y no participa en ningún cobro. Es el interruptor que esta propuesta enciende — sin inventar campos nuevos.
El interruptor dormido. `PaymentMethod.commission` existe, se administra y viaja al portal en cada carga. La propuesta no agrega un campo: le da significado al que ya está.
v1 sí cobraba el recargo, pero al confirmar mutaba el total de la orden
(total += fee), con un fallback de 8% hardcodeado en el backend y un 3%
hardcodeado aparte en el frontend. La deuda del cliente crecía después de pagar y el
precio del servicio dejaba de ser el precio del servicio.
v2 eliminó esa familia de mutaciones a propósito: el balance se calcula en un solo servicio, y la conciliación bancaria exige igualdad al centavo exacto por trigger de base de datos. El recargo vuelve — pero como línea con nombre, no como total que cambia solo.
El sistema financiero de v2 es de tres capas: lo que el cliente pagó (A), lo que el proveedor liquidó (B) y lo que llegó al banco (C). Con el recargo como línea, un pago de $500 por Stripe al 3% viaja así — y cada capa cierra sola, sin tolerancias nuevas:
Por qué B y C no se tocan. La liquidación ya maneja bruto/fee/neto arbitrarios: el batch suma lo que Stripe reporte y el banco se concilia contra el neto. Lo único que faltaba era poder decir, en la Capa A, cuánto del bruto era recargo.
El recargo nace como línea de cotización con tipo propio, dentro de la misma
transacción de base de datos que ya crea Transaction + Payment +
Receipt — atómico, idempotente y anulable como una sola unidad. Hay precedente
directo: la migración v1→v2 ya importó los recargos históricos como línea
«Recargo por método de pago». Lo que faltaba era el tipo con nombre.
PAYMENT_SURCHARGEEXTRA_CHARGE.
Dos razones duras: el rebuild de tarifas de fletes borra y reconstruye las líneas
EXTRA_CHARGE (el recargo se esfumaría al editar una tarifa), y sin tipo propio
el recargo se reportaría como ingreso de flete, invisible como negocio.PaymentMethod.commissioncreatePaymentRecord$transaction existente y detrás del mismo guard de idempotencia
(confirm del cliente y webhook de Stripe compiten hoy; gana uno solo, y la línea
viaja con el ganador). Total y pagado crecen por el mismo monto: el rollup cierra
exacto, sin tolerancias nuevas.createPaymentIntentbase × (1 + commission)) y el intent
guarda baseAmount + surchargeAmount en metadata para
trazabilidad. La verificación server-side valida el desglose contra el método —
el cliente nunca manda el porcentaje.INCOME_GATEWAY_SURCHARGEFEES_PROCESSOR (gasto). Hoy ese neto es invisible y siempre negativo.
Así lo hacen QuickBooks, Bill.com y el invoicing de Stripe, y así lo exigen las redes:
desglose visible antes de pagar, recargo como línea separada en el recibo,
tope de 3% (regla Visa/Mastercard en EE.UU.) y nunca por encima del costo real de
aceptación. El diseño lo respeta de fábrica: el % vive por método, es visible en cada
pantalla, y se apaga poniendo commission = 0. Contablemente es GAAP puro:
recargo = ingreso propio, fee del procesador = gasto — jamás neteados en silencio.
La regla de oro es que el cliente lo vea antes, no después. De cara al cliente la etiqueta es «Fee de servicio Mogos» — profesional y genérica, como los service fees de cualquier marketplace; «recargo» queda como concepto interno y contable. Aparece dos veces: como dato del método (al elegir cómo pagar) y como línea del desglose (antes de confirmar). El botón dice la cifra final — la misma que saldrá en el estado de cuenta.
¿Cómo quieres pagar?
El fee es un dato del método, no un castigo. Cada opción declara el suyo en tipografía tabular; los métodos sin fee lo dicen en verde — el incentivo a Zelle queda implícito, sin regañar a nadie.
Revisa tu pago
StripeEl botón dice la verdad completa. Abono y recargo en líneas separadas, el total en la placa de marca, y el CTA con la cifra exacta del cargo. Nada que descubrir después.
Después de pagar, el desglose no desaparece: la pantalla de éxito — y el comprobante — repiten las dos líneas. El abono amortiza la deuda del flete; el recargo queda como línea con nombre. Y de ahí en adelante el dinero viaja por las tuberías que ya existen.
¡Pago recibido!
Tu flete quedó al día. El comprobante llega a tu correo.
Dos líneas también en el comprobante. El recibo hereda el desglose: quien audite un pago ve el abono y el recargo por separado — exactamente lo que exigen las reglas de las redes de tarjetas.
Un recargo mal anulado deja una deuda fantasma; un recargo duplicado por un webhook repetido infla la cotización. Cada caso delicado tiene una regla — decidida ahora, no descubierta en producción.
El void desactiva el pago y anula su línea de recargo en la misma transacción. Total y pagado bajan juntos por el mismo monto: el balance vuelve solo a donde estaba. Sin línea huérfana, sin deuda fantasma.
Reembolso total: se devuelve el bruto ($515) y la línea de recargo se anula con él. Reembolso parcial: se devuelve lo reembolsado y la línea no se toca — el servicio de procesamiento ya se prestó. La misma regla aplica a disputas.
El recargo se calcula sobre lo que se paga, no sobre la deuda. Tres abonos por Stripe traen tres líneas, cada una atada a su pago. Quien mezcla métodos paga recargo solo por la parte que pasó por tarjeta.
El confirm del cliente y el webhook de Stripe ya compiten hoy y gana uno solo (índice único por intent). La línea nace dentro de ese mismo guard: webhook repetido, doble clic o reintento — una sola línea, siempre.
Las líneas EXTRA_CHARGE se borran y reconstruyen cuando se edita una
tarifa de flete. PAYMENT_SURCHARGE queda fuera de esa lista: editar
una tarifa jamás toca un recargo ya cobrado.
El porcentaje nunca viene del cliente: el server lo lee del método al crear el intent y lo re-valida al confirmar. Un portal viejo o un request manipulado no pueden cobrar un recargo distinto al configurado.
Con el recargo como categoría propia de ingreso, finanzas ve por primera vez las dos columnas juntas: lo cobrado por recargo contra el fee real que Stripe descontó. A 3% el recargo cubre ~98% del costo — el fee corre sobre el bruto y suma 30¢ fijos por cobro — y el tope de las redes impide subirlo más. La diferencia deja de ser una pérdida invisible y pasa a ser un número chico, conocido y decidido.
Pasarela · agosto 2026
finanzas · propuestaHoy ese −$21.90 es −$1,265.90: sin recargo, el fee completo sale del margen y ningún reporte lo muestra. Con la categoría propia, gerencia decide con el número en la mano — y el 98% del costo lo paga quien elige la tarjeta.
Sin tocar la conciliación. El panel de payouts (Bruto / Comisión / Neto) sigue idéntico: esto es una vista de reporting sobre categorías nuevas, no un cambio en el motor de matching.
La instrucción fue clara: no afectar la calidad del sistema de pagos. Esta es la lista explícita de lo que la propuesta deja exactamente como está — y es la lista que un QA puede verificar punto por punto.
- El rollup del balance — un solo servicio, tolerancia de $0.50 solo para el estado, montos siempre reales. Igual que hoy.
- La conciliación bancaria — trigger de centavo exacto, matching por neto de payout. Cero cambios en Capas B y C.
Transaction.feeAmount / netAmount— el fee real de Stripe se sigue registrando igual. El recargo no lo reemplaza: son ingreso y gasto, cada uno en su columna.- Los métodos sin recargo — Zelle, efectivo y transferencia tienen
commission = 0: su flujo, sus pantallas y sus recibos no cambian ni un píxel. - La idempotencia de pasarela — el índice único por intent y el guard confirm-vs-webhook quedan intactos; la línea solo se suma al ganador.
- El total del servicio — el precio del flete nunca muta. El recargo es una línea aparte, visible, anulable y auditable. Lo de v1 no vuelve.
El recargo entra por la puerta grande: una línea con nombre, no un total que cambia solo.
Un enum nuevo, un campo que ya existía y las tuberías de siempre. El cliente ve el desglose antes de pagar, el recibo lo repite, el flete nunca cambia de precio y la conciliación sigue cerrando al centavo. Y por primera vez, el costo de cobrar con tarjeta es un número que alguien decidió — no uno que nadie vio.