Referidos
Dale a cada usuario un enlace, registra quién llega por él y acredita una recompensa cuando se registran y cuando pagan.
El programa de referidos le da a cada usuario un enlace. Cuando alguien se registra después de seguirlo, las dos cuentas quedan ligadas y al que refirió se le acredita una recompensa fija; cada vez que la cuenta referida paga una factura de suscripción, se le acredita un porcentaje. Las recompensas son números que el kit guarda y muestra. Nada las paga: esa parte te toca construirla.
Enciéndelo
Cinco variables de entorno, leídas por config/features.php bajo referrals. Ninguna está en .env.example, así que agrega las que necesites.
| Llave | Variable de entorno | Valor por omisión | Valores | Qué cambia |
|---|---|---|---|---|
enabled |
FEATURE_REFERRALS_ENABLED |
false |
true, false |
Apagado: la entrada Referencias sale de la barra lateral de la cuenta, /account/referrals responde 404, ?referrer= se ignora, no se registra ningún referido ni recompensa, y "Suscripciones por referencias" sale del dashboard de administración. Los datos ya guardados se conservan. |
registration_reward |
FEATURE_REFERRALS_REGISTRATION_REWARD |
10 |
Un número | Se acredita al que refirió una sola vez cuando la persona referida se registra. 0 no crea recompensa de registro. |
subscription_reward_percent |
FEATURE_REFERRALS_SUBSCRIPTION_REWARD_PERCENT |
10 |
Un porcentaje | Parte de cada factura de suscripción pagada por la cuenta referida que se acredita al que refirió. 0 no crea recompensa de suscripción. |
currency |
FEATURE_REFERRALS_CURRENCY |
mxn |
Código ISO en minúsculas | Moneda de la recompensa de registro. También la moneda de respaldo cuando una factura de Stripe no trae ninguna. |
cookie_days |
FEATURE_REFERRALS_COOKIE_DAYS |
30 |
Días enteros | Cuánto tiempo el navegador del visitante recuerda a quien lo refirió después de seguir el enlace. Los valores menores a 1 se leen como 1. |
FEATURE_REFERRALS_ENABLED=true
FEATURE_REFERRALS_REGISTRATION_REWARD=10
FEATURE_REFERRALS_SUBSCRIPTION_REWARD_PERCENT=10
FEATURE_REFERRALS_CURRENCY=mxn
FEATURE_REFERRALS_COOKIE_DAYS=30
La recompensa de suscripción necesita planes y el webhook de Stripe, porque se crea a partir de invoice.paid. Mira Enciende los planes y la facturación. La recompensa de registro no necesita nada más.
El enlace de referido
https://your-project.test/?referrer=K7QP2XM4
El código es users.referral_code: ocho caracteres aleatorios en mayúsculas, único, creado la primera vez que el usuario abre la página de referidos o que tu código llama a $user->getOrCreateReferralCode(). $user->referralUrl() construye el enlace de arriba.
El parámetro referrer se lee en cualquier página, no sólo en la de inicio. El middleware App\Http\Middleware\CaptureReferralCode corre en cada petición web y, en un GET normal que no sea una llamada de Livewire ni JSON, le entrega la petición a App\Classes\Referrals:
- El código se recorta y se pasa a mayúsculas. Si ningún usuario tiene ese código, no pasa nada.
- Se guarda en la sesión bajo
referrals.referrer_code, y en una cookie llamadareferrer_codeque duracookie_daysdías. - En visitas posteriores sin código en la sesión, la cookie lo restaura y se vuelve a encolar, así que la ventana se reinicia cada vez que el visitante regresa.
Un visitante que sigue el enlace hoy y se registra dentro de la ventana de la cookie sigue quedando atribuido. Un código que llega al sitio con la bandera apagada se ignora, no se guarda.
Cuando la persona referida se registra
App\Observers\UserObserver::created() llama a $user->registerReferredUser() por cada usuario nuevo, sin importar cómo se creó. Lee el código de la sesión, luego de la cookie, encuentra a quien refirió y:
- No hace nada si no hay código, el código no coincide con ningún usuario, o quien refirió es el propio usuario nuevo.
- Crea una fila en
referrals:referrer_id,referred_id, elcodeusado yregistered_at. Un usuario puede ser referido una sola vez;referred_ides único. - Crea la recompensa de registro cuando
registration_rewardes mayor a cero: una fila enreferral_rewardscontyperegistration, elamountconfigurado, lacurrencyconfigurada y el id del usuario referido comosource_id, para que el mismo registro nunca se recompense dos veces.
Para la persona referida nada cambia: ni descuento, ni crédito, ni mención en pantalla.
Cuando la persona referida paga
Cada evento invoice.paid que Stripe manda por una suscripción llega al controlador de webhooks del paquete. Cuando el amount_paid de la factura es mayor a cero, despacha WeblaborMx\BillingCore\Events\SubscriptionPaid con el importe en unidades mayores, la moneda de la factura, el id de la factura y el id de la suscripción. App\Listeners\RecordSubscriptionPayment escucha, ignora las cuentas que no son de usuario y llama a $user->recordPaidSubscriptionReward($amount, $currency, $invoiceId):
- No se registra nada si la bandera está apagada, el importe es cero, el usuario no fue referido o
subscription_reward_percentes cero. - En otro caso, una fila en
referral_rewardscontypesubscription,amount= importe de la factura × porcentaje ÷ 100 redondeado a dos decimales,source_amount= el importe de la factura,percentage= el porcentaje,currency= la moneda de la factura en minúsculas ysource_id= el id de la factura en Stripe.
El par type + source_id es único por referido, así que un webhook entregado dos veces registra una sola recompensa. Cuenta cada factura: el primer pago, cada renovación y las facturas que generan los complementos de la suscripción. Los planes gratis y las pruebas no pagan nada, así que no acreditan nada. La recompensa se acredita en el momento en que llega el webhook; un webhook ausente o mal configurado significa que no habrá recompensas de suscripción.
Cuánto, y en qué moneda
La recompensa de registro siempre está en FEATURE_REFERRALS_CURRENCY. La recompensa de suscripción está en la moneda de la factura, sin importar en qué se cotizó el plan. Quien refirió cuentas que pagan en dos monedas tiene, por lo tanto, dos totales, y el kit nunca convierte uno en el otro: rewardTotals() agrupa por moneda y cada pantalla lista una cifra por moneda, con formato $ seguido del importe y el código, por ejemplo $150.00 MXN.
Cómo se guarda
| Tabla | Columnas | Notas |
|---|---|---|
users |
referral_code |
Nulable, único, 32 caracteres. |
referrals |
referrer_id, referred_id, code, registered_at |
Una fila por usuario referido. |
referral_rewards |
referral_id, type, amount, source_amount, percentage, currency, source_id |
type es registration o subscription. Único en referral_id, type, source_id. |
No hay columna de saldo, ni tabla de pagos, ni cargos. Los totales que ve un usuario son SUM(amount) sobre sus recompensas, agrupadas por moneda, calculados en cada carga de página. Por eso la pantalla habla de "dinero virtual". Cuando construyas los pagos, agrega tu propia tabla que registre lo pagado y réstalo de estos totales.
Las piezas que llamas desde código:
| Dónde | Método | Devuelve |
|---|---|---|
User (trait App\Traits\HasReferrals) |
getOrCreateReferralCode() |
El código, creándolo si falta. |
referralUrl() |
El enlace completo. | |
referrals() |
Las filas Referral donde este usuario es quien refirió. |
|
referredByReferral() |
El único Referral donde este usuario es el referido, o null. |
|
rewardTotals() |
Colección con la moneda como llave y los importes sumados. | |
registerReferredUser() |
Lo que llama el observer. Devuelve el Referral o null. |
|
recordPaidSubscriptionReward($amount, $currency, $sourceId) |
Lo que llama el listener. Devuelve el ReferralReward o null. |
|
App\Models\Referral |
referrer(), referred(), rewards() |
Relaciones. |
reward_totals |
Atributo: las recompensas de este referido sumadas por moneda. | |
App\Classes\Referrals |
rememberCode($code) |
Guarda un código en sesión y cookie a mano, por ejemplo después de tu propia landing. |
enabled() |
La bandera. |
Lo que ve el usuario
Referencias, con un ícono de regalo, aparece en la barra lateral de la cuenta y abre /account/referrals. La página tiene tres tarjetas:
- "Recomienda y gana": la recompensa de registro y el porcentaje de suscripción tal como están configurados, el total de dinero virtual generado por moneda y cuántos usuarios se registraron con el enlace.
- "Tu enlace de referencia": el enlace en un campo de sólo lectura y un botón Copiar enlace, con la nota de que un visitante que se registre después sigue quedando asociado durante varios días.
- "Usuarios registrados con tu enlace": una fila por usuario referido con nombre y correo, la fecha de registro y lo que ese usuario generó, por moneda. Una cuenta referida eliminada se muestra como usuario eliminado.
La persona referida no ve nada sobre el referido en ningún lado.
Lo que ve el administrador
El dashboard de administración, /admin, ofrece Suscripciones por referencias en su selector de métrica mientras la bandera está encendida. Dibuja dos series en el rango de fechas elegido: nuevas inscripciones por referencia, a partir de referrals.registered_at, y suscripciones de referencia pagadas, contando las recompensas subscription por la fecha en que se crearon.
Eso es todo. No hay recurso de administración para referidos ni recompensas, el formulario de usuario no muestra el código de referido y nada permite a un administrador editar o cancelar una recompensa. Las correcciones se hacen en la base de datos o con código que agregues.