Skip to content

Happy path: la venta de Tienda Frescura

Una historia con 6 personajes que muestra el módulo de comisiones en acción — desde el primer click en el landing hasta el pago del bono a los 3 meses.


🎭 Cast

PersonajeRolFunción
Tienda FrescuraCliente (tenant)Supermercado que paga la suscripción mensual
Pablo RamírezSDR — Sales Development RepProspecta y trae el lead. Co-participante de la venta
María GonzálezAE — Account ExecutiveCierra el deal. Participante primaria
Carlos ManagerGerente de ventasManager directo de María. Cobra override
Diana DirectorDirectora regionalManager de Carlos. Cobra override de segundo nivel
Sopinf Tech LLCEl MSPDueño del producto SipSop. Retiene el resto del revenue

🌳 Jerarquía

Diana Director (override 5%)
  └── Carlos Manager (override 10%)
        └── María González (AE, 70% del split)

Pablo Ramírez (SDR, 30% del split) — no tiene manager en este ejemplo

Diana y Carlos ganan override sobre la comisión que le corresponde a María (no sobre lo de Pablo, porque Pablo no está en su cadena de reportes).


💰 La venta — números reales

Tienda Frescura contrata el plan Business:

ComponentePrecioSource Stripe
Base plan$79.00stripe_base_price_id
5 teléfonos × $4.80$24.00stripe_phone_price_id
1 línea SIP$12.00stripe_line_price_id
Overage international$3.20stripe_overage_price_id
Total mensual$118.20

Términos acordados con los reps al crear la asignación:

  • Participantes: María 70% (role: AE) + Pablo 30% (role: SDR)
  • % por componente: base 5% · phones 3% · lines 2% · overage 10%
  • Bono one-time: $200, vesting 3 meses
  • Basis: gross (sin descontar Stripe fees)

⚙️ Configuración en el sistema

commission_reps

María González — email: maria@sopinf.com — managerId: carlos.id
Carlos Manager — email: carlos@sopinf.com — managerId: diana.id — overridePercent: 10
Diana Director — email: diana@sopinf.com — managerId: null — overridePercent: 5
Pablo Ramírez  — email: pablo@sopinf.com — managerId: null — overridePercent: 0

commission_assignment para Tienda Frescura

tenantId: tienda-frescura.id
recurringPercent: 5 (fallback global — no se usa en modo breakdown)
basis: gross
startsAt: 2026-02-01
oneTimeAmountCents: 20000 ($200)
recurringPercentBase: 5
recurringPercentPhones: 3
recurringPercentLines: 2
recurringPercentOverage: 10
participants:
  - María González: sharePercent=70, role='AE'
  - Pablo Ramírez: sharePercent=30, role='SDR'

🔄 Flujo mensual (meses 1, 2, y 3)

Día de facturación: Stripe cobra a Tienda Frescura

Stripe emite el invoice. El webhook invoice.paid llega al API. El handler descompone el invoice en 4 líneas y crea 4 revenue_events:

revenue_events para Tienda Frescura, período 2026-02:
  source: stripe_invoice | component: base     | amountUsdCents: 7900
  source: stripe_invoice | component: phones   | amountUsdCents: 2400
  source: stripe_invoice | component: lines    | amountUsdCents: 1200
  source: stripe_invoice | component: overage  | amountUsdCents: 320
  Total bruto: $118.20

Día 1 del mes siguiente: cron genera statements

El job commissions-monthly corre a las 3am UTC y llama materializeStatementsForPeriod('2026-02').

Cálculo del calculator por componente:

El motor bucketea los revenue events por componente y aplica el % correspondiente:

ComponenteRevenue% María (70%)% Pablo (30%)
base$79.005% × $79 × 0.70 = $2.775% × $79 × 0.30 = $1.19
phones$24.003% × $24 × 0.70 = $0.503% × $24 × 0.30 = $0.22
lines$12.002% × $12 × 0.70 = $0.172% × $12 × 0.30 = $0.07
overage$3.2010% × $3.20 × 0.70 = $0.2210% × $3.20 × 0.30 = $0.10
Total$118.20$3.66$1.57

Nota: los centavos usan Math.round(). Puede haber diferencia de ±1¢ por rounding.

Override walk para los line items de María:

Carlos Manager (10% override, manager de María):

  • $3.66 × 10% = $0.37 (override sobre los line items base de María)

Diana Director (5% override, manager de Carlos):

  • $3.66 × 5% = $0.18 (override sobre la comisión original de María — sin compounding)

Pablo no tiene manager, así que no genera overrides hacia arriba.

Statements generados (mes 1-3, solo recurring):

RepTipoAmount
María Gonzálezrecurring split$3.66
Pablo Ramírezrecurring split$1.57
Carlos Manageroverride sobre María$0.37
Diana Directoroverride sobre María$0.18

Sopinf retiene: $118.20 - $3.66 - $1.57 - $0.37 - $0.18 = $112.42


🎁 Mes 4 — vesting del bono one-time

startsAt = 2026-02-01. oneTimeQualificationMonths = 3. El cron del 1ro de mayo de 2026 genera el statement de abril 2026. qualifiedAt = 2026-05-01, que cae en [2026-04-01, 2026-04-30].

El calculator detecta que la asignación calificó para el bono one-time este período. Incluye un line item kind='one_time' por $200 total, prorateado por share:

RepRecurringOne-timeOverride one-timeTotal mes 4
María González$3.66$140.00 (70%)$143.66
Pablo Ramírez$1.57$60.00 (30%)$61.57
Carlos Manager$0.37$14.00 (10% de $140)$14.37
Diana Director$0.18$7.00 (5% de $140)$7.18

Al finalizar el statement del mes 4, el servicio marca commission_assignments.oneTimePaidAt = '2026-04-01'. El bono no vuelve a aparecer en meses futuros.


📅 Timeline completo

Día 0:   Pablo detecta oportunidad. Comparte landing.sipsop.net?ref=pablo-ramirez
         con Tienda Frescura. (En este ejemplo, Pablo no tiene ref code — María cierra.)

Día 5:   María contacta a Tienda Frescura. Convence al dueño de hacer el demo.

Día 12:  Tienda Frescura llena el form del landing con ?ref=maria-gonzalez.
         Cookie first-touch se establece (90 días).
         POST /api/v1/leads → lead.commissionRepId = maría.id

Día 15:  Admin aprueba el lead y crea el tenant.
         Signup service detecta lead.commissionRepId → crea commission_assignment automáticamente.
         Log: action='lead_converted'

Día 15:  Admin edita la asignación: agrega Pablo como 30% SDR, ajusta María a 70% AE.
         replaceParticipants → log: action='admin_reassigned'

Día 15:  Tienda Frescura activa suscripción en Stripe (plan Business).

Día 31:  Primer cobro. webhook invoice.paid → 4 revenue_events (base, phones, lines, overage)

Día 60:  Segundo cobro. 4 más revenue_events.

Día 90:  Tercer cobro. 4 más revenue_events.

Día 1/3: Cron de marzo materializa statements de febrero.
Día 1/4: Cron de abril materializa statements de marzo.
Día 1/5: Cron de mayo materializa statements de abril — incluye bono one-time.

Día 102: María y Pablo abren /seller/dashboard, ven statements de los 4 meses.
         Descargan PDFs de sus statements.

Día 110: Admin revisa statements en /admin/commissions/statements.
         Finaliza cada uno (oneTimePaidAt queda marcado al finalizar el de mes 4).
         Marca como pagado: paymentMethod='ach', paymentReference='ACH-20260510'.

Flujo de dinero

mermaid
flowchart TD
    A[Tienda Frescura\n$118.20/mes] -->|Stripe invoice.paid| B[revenue_events\n4 eventos por componente]
    B --> C[commission-calculator\ncalculateForPeriod]
    C --> D[Statement María\n$3.66 recurring\n+ $140 one-time mes 4]
    C --> E[Statement Pablo\n$1.57 recurring\n+ $60 one-time mes 4]
    C --> F[Statement Carlos\noverride 10% sobre María\n$0.37 recurring]
    C --> G[Statement Diana\noverride 5% sobre María\n$0.18 recurring]
    A -->|retiene| H[Sopinf Tech LLC\n$112.42]

Statement PDF de María (mes 4)

El PDF generado por renderStatementPdf incluye algo así:

STATEMENT — María González
Período: 2026-04-01 / 2026-04-30
Estado: FINALIZED

TENANT              KIND               COMPONENTE  REVENUE     RATE   AMOUNT
Tienda Frescura     recurring_percent  base        $79.00      5%     $2.77
Tienda Frescura     recurring_percent  phones      $24.00      3%     $0.50
Tienda Frescura     recurring_percent  lines       $12.00      2%     $0.17
Tienda Frescura     recurring_percent  overage     $3.20       10%    $0.22
Tienda Frescura     one_time           —           —           —      $140.00

SUBTOTAL RECURRING:                                                    $3.66
SUBTOTAL ONE-TIME:                                                   $140.00
SUBTOTAL OVERRIDE:                                                     $0.00
TOTAL:                                                               $143.66

Statement PDF de Carlos (mes 4)

Carlos ve sus override line items con el rep fuente:

STATEMENT — Carlos Manager
Período: 2026-04-01 / 2026-04-30
Estado: FINALIZED

TENANT              KIND      SOBRE            COMPONENTE  RATE   AMOUNT
Tienda Frescura     override  ↗ María González base        10%    $0.28
Tienda Frescura     override  ↗ María González phones      10%    $0.05
Tienda Frescura     override  ↗ María González lines       10%    $0.02
Tienda Frescura     override  ↗ María González overage     10%    $0.02
Tienda Frescura     override  ↗ María González one_time    10%    $14.00

SUBTOTAL RECURRING:                                                    $0.37
SUBTOTAL ONE-TIME:                                                     $0.00
SUBTOTAL OVERRIDE:                                                    $14.37
TOTAL:                                                                $14.37

¿Por qué first-touch? Incentiva a los reps a traer leads tempranos en el ciclo de ventas. El SDR que inicia la conversación recibe crédito aunque el AE cierre el deal semanas después. El split 70/30 entre María y Pablo reconoce ambas contribuciones explícitamente, sin disputas.

Cuidado con dobles invitaciones. Si Pablo también tenía un ref code y Tienda Frescura visitó el landing primero con el link de Pablo, la cookie se habría establecido con pablo-ramirez. El form enviaría ese ref code. María habría quedado fuera de la atribución automática. Por eso el admin puede hacer override manual vía commissions.leads.setRep antes de la conversión.

Override no duplica la comisión del IC. Carlos recibe $14.37 adicionales — Sopinf paga ese monto extra, no se descuenta de lo de María. El override es comisión adicional del MSP al manager, no un split del IC.


Documentación de SipSop. Producto operado por Sopinf Tech LLC.