propuesta · ago 2026

Pagos · finanzas

El costo de cobrar, con nombre propio.

Cobrar cuesta en casi todos los canales: Stripe descuenta ~2.9% + 30¢ del payout, el efectivo hay que bancarizarlo, y hoy Mogos absorbe ese costo sin que nadie lo vea. El campo Comisión del admin existe desde v1, viaja hasta el portal — y nadie lo usa. Esta propuesta lo enciende como fee de procesamiento propio de Mogos: un porcentaje por método — cualquier método, decidido por gerencia — con desglose visible antes de cobrar, línea separada en el recibo, y una línea contable de primera clase que hace que los libros cierren al centavo. No es un recargo del banco: es parte del precio de Mogos. La conciliación no se toca.

Modelo
Línea PAYMENT_SURCHARGE
El %
PaymentMethod.commission
Alcance
Cualquier método
Conciliación
Sin cambios
Tolerancias nuevas
Cero
01La comisión que nadie lee
payment_methods.commission

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 netAmountescritos en cada pago, leídos por nadie. Y no es solo tarjeta: bancarizar el efectivo también cuesta, y ningún canal registra ese costo como negocio. Resultado: la plataforma sabe exactamente cuánto le cuesta cobrar — y lo absorbe igual.

Método de pago · Stripe

admin · hoy
Stripe
3%

El 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.

Se muestra en el portalNo
Se suma al cobroNo
Aparece en el reciboNo

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á.

Lo que enseñó v1 — y lo que no se repite

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.

02La regla del centavo
3 capas · match exacto

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:

Capa ACliente · cotización
Deuda del flete$500.00
+ línea Fee de servicio 3%+$15.00
Pago registrado (bruto)$515.00
515 pagado = 515 adeudado
Capa BStripe · payout
Bruto cobrado$515.00
Fee real de Stripe−$15.24
Neto liquidado$499.76
El payout absorbe el recargo solo
Capa CBanco · conciliación
Crédito bancario$499.76
Match contra payoutexacto
Tolerancia aplicada$0.00
Trigger de centavo: intacto

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. Con métodos manuales (Zelle, efectivo) no hay Capa B de procesador: el bruto entra completo y se concilia igual. Lo único que faltaba era poder decir, en la Capa A, cuánto del bruto era fee.

03Una línea de primera clase
LineItemTypeEnum.PAYMENT_SURCHARGE

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.

El tipo
PAYMENT_SURCHARGE
Nuevo valor del enum de líneas — no el genérico EXTRA_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.
El porcentaje
PaymentMethod.commission
El campo que ya existe — por método y sin categorías. Cualquier método puede llevar fee: Stripe por la comisión que descuenta, el efectivo por el costo de bancarizarlo, Zelle si gerencia lo decide. 0 = sin fee, y es configuración, no regla: se cambia desde el admin, sin tocar código y sin tope.
Dónde nace
los 3 escritores
Un pago entra por tres caminos y la línea nace en los tres, siempre dentro del $transaction que ya crea el pago: pasarela (createPaymentRecord, detrás del guard confirm-vs-webhook), registro manual del admin (registerAdminPayment) y verificación Zelle (el flujo «ya pagué» del portal). Total y pagado crecen por el mismo monto: el rollup cierra exacto, sin tolerancias nuevas.
El cobro
createPaymentIntent
Solo pasarela: Stripe cobra el bruto (base × (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. En los caminos manuales el % se lee igual del método al crear el pago.
El ingreso
INCOME_SERVICE_FEE
Nueva categoría en el export contable (QBO), separada del ingreso de fletes. Por primera vez el spread es visible: fee cobrado (ingreso) contra el costo real del canal — FEES_PROCESSOR en pasarela, bancarización en efectivo. Hoy ese neto es invisible y siempre negativo.
Fee de servicio, no surcharge de tarjeta

Esto no es el surcharge que regulan las redes (ese repasa el costo de aceptación de la tarjeta y vive topado): es un fee de procesamiento propio, como el service fee de cualquier marketplace — parte del precio de Mogos, decidido por gerencia, método por método, sin tope regulatorio. Lo que el banco del cliente le cobre a él por usar su tarjeta es asunto del cliente y no aparece aquí.

Del estándar de industria se conserva lo que importa: desglose visible antes de pagar, fee como línea separada en el recibo, y GAAP puro — fee = ingreso propio, costo del canal = gasto, jamás neteados en silencio. Se apaga poniendo commission = 0.

04Cero sorpresas en el portal
apps/payments-portal

Dos reglas de oro. Una: el cliente ve el total antes de pagar, y paga exactamente lo que ve. Dos: ningún método se compara con otro — el selector no muestra fees ni incentivos; el fee aparece una sola vez, como línea del desglose, cuando el método ya está elegido. 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. El botón dice la cifra final — la misma que saldrá en el estado de cuenta.

elegir método · sin comparar

Las opciones son solo opciones. Ningún método anuncia fee ni descuento: aquí no se dirige la elección. El desglose llega en el paso siguiente, ya con el método elegido.

confirmar · el desglose

El botón dice la verdad completa. Abono y fee 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.

También en Zelle y efectivo

El mismo desglose aplica a los métodos manuales. Si Zelle lleva fee, el portal muestra abono + fee + total a transferir antes de que el cliente mande el dinero — y ese total es el que se verifica al llegar. Cuando el admin registra un pago de oficio (efectivo en oficina, transferencia reportada), el formulario de registro muestra el mismo desglose con el % del método: el cliente siempre paga lo que ve, por cualquier camino que entre el pago.

05El recibo y el viaje del dinero
dos líneas · un cargo

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.

Dos líneas también en el comprobante. El recibo hereda el desglose: quien audite un pago ve el abono y el fee por separado — dos líneas, un cargo, la misma historia en portal, recibo y contabilidad.

05·bEl estado de cuenta del cliente
apps/client · el fee viaja con su pago

La cotización crece por cada línea de fee, así que un flete de $1,000 pagado dos veces —$100 con tarjeta al 10%, $100 al día siguiente con un método al 20%— registra un total de $1,030. Si el cliente ve ese número huérfano, hace la resta equivocada («pagué $230, me quedan $800… ¿o $770?»). La regla que lo impide: el fee viaja con su pago, no con el flete. El cliente ancla en dos números — su flete ($1,000) y lo que le queda ($800) — y cada fee aparece pegado al pago que lo generó, congelado al % de su método en su momento, jamás mezclado en el precio del servicio.

Tu flete · FLETE-8241

client · estado de cuenta
Tu flete$1,000.00
Fees de servicio (2 pagos)+$30.00
Total$1,030.00
Pagado$230.00
Restante$800.00

Historial: 9 ago · Tarjeta — $110.00 (abono $100 + fee 10%) · 10 ago · Otro método — $120.00 (abono $100 + fee 20%). Cada línea nace atada a su pago con su % congelado: el fee de ayer nunca se recalcula con la tarifa de hoy.

Ninguna resta mental posible da $890 ni $770. El precio del flete es visible como precio, los fees como costo de los pagos ya hechos, y el restante siempre es el del flete: pagó $200 de $1,000 ⇒ quedan $800. Anular el segundo pago devuelve su línea de $20 y el restante vuelve a $900 exacto.

06Los bordes, resueltos de fábrica
void · refund · parciales

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.

Anulación de pago

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 y disputa

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.

Pagos parciales

El fee 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 fee solo por la parte que pasó por un método con fee configurado.

Idempotencia

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.

Rebuild de tarifas

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.

Validación server-side

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 fee distinto al configurado.

Registro manual del admin

registerAdminPayment crea Transaction + Payment + Receipt en una sola $transaction Serializable — la línea de fee nace ahí mismo, con el % del método al momento del registro. El admin ve el desglose antes de confirmar, igual que el cliente en el portal.

Verificación Zelle

El «ya pagué» del portal muestra el total a transferir con fee incluido; la verificación compara lo recibido contra ese total y la línea nace con el pago verificado, con el % que el cliente vio al reportar. Una sola línea aunque el flujo se reintente.

07El spread, por fin visible
ingreso vs gasto

Con el fee como categoría propia de ingreso, finanzas ve por primera vez las dos columnas juntas: lo cobrado por fee de servicio contra el costo real de cada canal — la comisión de Stripe, el costo de bancarizar el efectivo. El % de cada método es una decisión comercial: puede cubrir el costo exacto, quedarse corto o dejar margen, y el reporte muestra el spread real para ajustarlo con el número en la mano. La diferencia deja de ser una pérdida invisible y pasa a ser un número conocido y decidido.

Pasarela · agosto 2026

finanzas · propuesta
Cobros con tarjeta41 pagos · $42,710.00
Fee de servicio cobrado · INCOME_SERVICE_FEE+$1,244.00
Fee real de Stripe · FEES_PROCESSOR−$1,265.90
Spread del mes−$21.90

Hoy ese −$21.90 es −$1,265.90: sin fee, el costo completo sale del margen y ningún reporte lo muestra. Con la categoría propia, gerencia ve el spread por canal y ajusta el % de cada método con el número en la mano.

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.

08Lo que no se toca
la garantía de calidad

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 en commission = 0 — cualquier método que quede en cero conserva su flujo, sus pantallas y sus recibos sin cambiar ni un píxel. El cero es configuración, no categoría.
  • 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 fee de servicio 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 — en los tres caminos por donde entra un pago. El cliente ve el desglose antes de pagar y paga exactamente lo que ve, 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 es un número que alguien decidió — no uno que nadie vio.