Vender suscripciones con PayPal

Buscando en la red sobre el poder que tiene perl que, aunque Uds. no lo crean es inmenso, encontré el siguiente tutorial desarrollado por Uriel Lizama en el cual nos da las pautas para vender membrecías de forma sencilla mediante PayPal, cuyo servicio se puede configurar en menos de una hora en nuestro sitio.

Tu cuenta en PayPal

Como es lógico lo primero que tienes que hacer es crear tu cuenta en PayPal, es realmente muy sencillo y puedes crearla en el siguiente link:

https://www.paypal.com/row/mrb/pal=EC6ML8VKFAJ6E

Una vez que hayas creado tu cuenta de PayPal ahora podemos empezar a configurar todo.

Creando tu área de miembros….

Normalmente cuando vendemos membrecías a nuestro sitio lo que hacemos es crear un área especial en donde solamente pueden entrar miembros. Para poder accesar, nuestros miembros deben de usar una clave y contraseña la cual les es proporcionada una vez que hayan hecho el pago de su membrecía, les recomiendo el siguiente tutorial en donde puedes conocer como configurar su propio directorio protegido:

http://perlenespanol.baboonsoftware.com/archives-tut/000165.html

Una vez que ya hayas probado que tu directorio protegido funciona de manera correcta, ahora es momento configurar nuestra interface con PayPal.

Usando el IPN de PayPal

Vender membrecías con PayPal es sumamente sencillo, todo lo que tenemos que hacer es crear una vía de comunicación entre PayPal y nuestro servidor. PayPal se encarga de dar de alta y de baja a nuestros usuarios dependiendo del término de sus membrecías, por lo que una vez que hayamos configurado todo ya no nos tenemos que preocupar.

La forma en que PayPal se comunica con nuestro servidor para avisarnos que hay que dar de alta o de baja un usuario es por medio de una tecnología que se llama IPN.

El IPN o Instant Paymen Notification de PayPal es el medio por el cual PayPal se comunicará de manera automática e instantánea con tu sitio para notificar de cambios. A continuación podrán ver un gráfico que te muestra cómo funciona esto:

 

1.JPG

¿Cómo funciona el IPN?

1. El pago de un usuario o un refund activa el IPN.

2. PayPal hace un post de con campos de un FORM HTML al URL que pongas en tu perfil. Este POST es el corazón de IPN. Dentro de la notificación vienen incluidas la información de pago de tu cliente (como nombre del cliente y monto de pago).

3. Tu servidor debe entonces validar la notificación para asegurarse que es legítima.

Para configurar el URL de nuestro IPN debemos de accesar a nuestra cuenta de PayPal.

Ahí nos debemos de dirigir a Profile, ahí bajo Selling Preferences encontraremos una liga que dice Instant Payment Notification Preferences.

Muy bien, ahí debemos de ingresar el URL de nuestro CGI de IPN y activarlo. Dependiendo del lugar en donde quieras poner tu CGI es el URL que debes de poner, por ejemplo:

“http://www.misitio.com/cgi-bin/paypal.cgi”

 2.JPG

 

Creando nuestro programa de IPN

Ahora vamos a la parte más delicada de todo el proceso, que es la creación de nuestro programa de IPN. Este programa es el CGI que se va a encargar de realizar la comunicación de PayPal y de llevar a cabo las tareas de alta y de baja de nuestros miembros.

Recuerda que este CGI es el cual diste de alta en tu Perfil de PayPal, así que recuerda guardarlo en el mismo URL.  Nuestro CGI consta de varias partes, primero recibimos los datos, luego verificamos que los datos realmente provengan de PayPal y finalmente decidimos que hacer de acuerdo con los datos que PayPal nos ha enviado.

Como siempre, primero empezamos con la cabeza de nuestro CGI, usando el pragma strict y cargando los módulos necesarios.  Recuerda cambiar la primera línea del script #!/usr/bin/perl con el path de Perl en tu servidor.

#!/usr/bin/perl

use strict;

# Cargamos los Módulos

use CGI::Carp;

use CGI qw(:standard escapeHTML);

use LWP::UserAgent;

# CGI.pm versioning issue

$CGI::USE_PARAM_SEMICOLONS = 0;

 

Después lo que vamos a hacer es configurar nuestras variables globales, estas las debes de customizar de acuerdo a tu información personal:

# URL a PayPal
my $PAYPAL_URL = 'http://www.paypal.com/cgi-bin/webscr';
 
#Archivo .htpasswd
my $HTPASSWD = '/home/ruta/a/mi/.htpasswd';
 
# Dirección de nuestro sendmail
my $SENDMAIL_PATH = '/usr/sbin/sendmail';
 
# Dirección donde queremos las notificaciones de error
my $ADMIN_EMAIL = 'notificaciones@misitio.com';
 
# Nuestro Email de la cuenta de PayPal
my @PAYMENT_EMAILS = ('pagos@misitio.com');
# -------------------------------------------------------------------

Veamos con cuidado cada una de las variables.

$PAYPAL_URL �sta variable no la debes de modificar, a menos que estés bajo un servidor https, si ese es el caso entonces debes de conectarte a PayPal por medio de https (https://www.paypal.com/cgi-bin/webscr).

$HTPASSWD Aquí debes de poner la ruta completa a tu archivo .htpasswd, recuerda que lo debes de tener configurado.

$SENDMAIL_PATH El CGI va a estar configurado para mandarte mails de cualquier error que pueda haber durante el proceso. Aquí debes de poner la ruta al sendmail de tu servidor.

$ADMIN_EMAIL Email donde quieres recibir las notificaciones de errores que pudieron haber surgido en el CGI. Es muy importante que pongas un mail que cheques constantemente, pues de esta manera podrás revisar en caso de cualquier error.

@PAYMENT_EMAILS Cuando activas tu cuenta en PayPal tu cuenta es el email que registraste, aquí lo debes de poner. Es muy importante que lo pongas bien, de lo contrario todas las transacciones serán rechazadas.

Explorando dentro del script de IPN

Después de definir todas las variables, iniciamos el proceso llamando a nuestra subrutina principal main().

sub main {

         # Verificamos el IPN

        if (verificar_ipn()) {

           # Ha sido verificado vamos a procesarlo

           procesar_ipn();

        }

         # IPN was successfully processed

        respuesta(1);

}

 
La subrutina principal es muy sencilla, lo primero que hacemos es verificar el IPN, si es correcto entonces los procesamos llamando a la subrutina procesar_ipn(), finalmente damos la respuesta.

La verificación del IPN es sumamente importante, pues nos permite comprobar que PayPal fue el que realmente mandó la notificación. Si no tuviéramos la comprobación, cualquiera podría mandar notificaciones y dar de alta membrecías no permitidas. 

sub verificar_ipn {

    # Nuevo UserAgent

    my $ua = new LWP::UserAgent;

    # Creamos el request

    my $req = new HTTP::Request(”POST”, $PAYPAL_URL);

       $req->content_type(”application/x-www-form-urlencoded”);

       $req->content(query_string() . “&cmd=_notify-validate”);

     # Recibimos la respuesta

    my $resp = $ua->request($req);

     # Checamos si fue exitosa la respuesta

    if (($resp->is_success) && ($resp->content eq “VERIFIED”)) {

        return 1;

    } else {

        # Intentamos identificar el error

        if (($resp->is_success) && ($resp->content eq “INVALID”)) {

            procesar_error(”La notificación recibida no fue de PayPal “.

             “- El mensaje fue ignorado “, “verificación de IPN”, 0, 0);

        } else {

            procesar_error(”La notificación no pudo ser procesada”,

             “verificación de IPN”, 1, 0);

        }

        return undef;

    } 

}

Lo que estamos haciendo es mandando a PayPal todos los campos recibidos incluyendo el campo cmd=_notify-validate que le indica a PayPal que estamos pidiendo una verificación. Entonces PayPal nos va a regresar una respuesta, ya sea VERIFIED indicando que la notificación si fue enviada por ellos o INVALID indicando que la notificación no salió de PayPal.

Si la respuesta es correcta entonces seguimos con el proceso, de lo contrario llamamos a nuestra subrutina procesar_error(); que es la encargada de manejar todos los errores que surjan durante el proceso.

Seguimos con el procesamiento de nuestro IPN por medio de la subrutina procesar_ipn():

sub procesar_ipn {

         # Nueva membresía

        if ((param(”txn_type”) eq “subscr_signup”) && (verificar_cuenta())) {

                # agregamos el usuario

                activar_usuario(param(”username”),param(”password”));

        } elsif (param(”txn_type”) eq “subscr_eot”) {

                # eliminamos al usuario

                desactivar_usuario(param(”username”));

        } else {

                # ignoramos el mensaje

        } 

}

La subrutina se encarga de ver que es lo que PayPal está notificando. Para hacer esto checa el campo txn_type. En este caso si el campo tiene un valor de subscr_signup entonces significa que PayPal está notificando una nueva membresía, en cuyo caso activamos al usuario llamando a la subrutina activar_usuario(), al llamar la subrutina manda dos variables como argumentos el username y el password, los cuales fueron proporcionados por medio de PayPal de manera automática y que el usuario usará para ingresar a la página protegida.

En caso de que el campo tenga un valor de subscr_eot, entonces PayPal nos está notificando que la cuenta debe de ser desactivada, por lo que llamamos a la subrutina desactivar_usuario(), y enviamos a la subrutina el campo username como argumento.

Si te das cuenta cuando vamos a dar de alta un usuario antes pedimos verificar la cuenta, esto lo puedes ver en la siguiente línea:

if ((param(”txn_type”) eq “subscr_signup”) && (verificar_cuenta())) {

La subrutina verificar_cuenta() se encarga de verificar si el pago fue hecho a una de tus cuentas, recuerda que esto lo configuras en la variable @PAYMENT_EMAILS. Esto es muy importante para evitar dar de alta membrecías que no te corresponden, aunque esto es muy poco probable, vale la pena comprobarlo:

 

sub verificar_cuenta {

     # validamos que el pago se haya realizado a nuestra cuenta

    my $valid = undef;

     for my $pay_mail (@PAYMENT_EMAILS) {

        if (param(”receiver_email”) eq $pay_mail) {

            $valid = 1;

            last;

        }

    }

    if (!$valid){

        procesar_error(”Se recibió un IPN de una cuenta que no es tuya “.

                        “- El mensaje fue ignorado.”, “validación de email “, 0, 0);

        return undef;

    }

 return 1; 

}

Ahora vamos a checar nuestras subrutinas encargadas de dar de alta y de baja a nuestros usuarios. Primero demos un vistazo a la subrutina encargada de dar de alta a los usuarios:

sub activar_usuario{ 

my $user = shift;

my $pass = shift;

#Verificamos que el usuario no exista ya

my $existe = undef;

 open my $in, ‘<’, $HTPASSWD

   or procesar_error(”No se pudo abrir archivo .htpasswd – $!”,

                       “abrir htpasswd”, 0, 1);

    while(my $line = <$in>){

        my ($auser,$apass) = split(/\:/, $line);

            if($auser eq $user){

                $existe = 1;

                last;

            }

     }

close $in;

 if($existe){

    # El usuario si existe, mandamos error

    procesar_error(”El usuario $user ya existe “.

      “- No se ha hecho ninguna acción”, “crear usuario”, 0, 1);

    return 1;

}else{

    # Introducimos el usuario a nuestro .htpasswd

    open my $out, ‘>>’, $HTPASSWD

        or procesar_error(”No se pudo abrir archivo .htpasswd – $!”,

                           ”abrir htpasswd”, 0, 1);

        print {$out} $user . “:” . $pass;

        print {$out} “\n”;

    close $out;

    return 1;

} 
}

Es sumamente sencillo lo que hacemos, primero recibimos el username y pass enviados al llamar la subrutina. Después de ello abrimos nuestro .htpasswd y checamos si no existe ya el username que queremos dar de alta, en caso de que exista notificamos acerca de esto y ya no realizamos ninguna acción.

Si el usuario aún no existe, entonces introducimos el nuevo usuario y contraseña dentro de nuestro .htpasswd, ya a partir de ese momento podrá tener nuestro usuario acceso a la página protegida.

Como podrás ver no hay necesidad de encriptar la contraseña, pues PayPal ya nos manda la contraseña encriptada. Seguimos ahora con la subrutina encargada de desactivar la cuenta:

sub desactivar_usuario{

my $user = shift;

open my $in, ‘<’, $HTPASSWD

   or procesar_error(”No se pudo abrir archivo .htpasswd – $!”,

                      “abrir htpasswd”, 0, 1);

my @usuarios = <$in>;

close $in;

 # Introducimos el usuario a nuestro .htpasswd

    open my $out, ‘>’, $HTPASSWD

          or procesar_error(”No se pudo abrir archivo .htpasswd – $!”,

                             “abrir htpasswd”, 0, 1);

        for my $linea_usuario(@usuarios){

            chomp($linea_usuario);

            my($auser,$apass) = split(/\:/, $linea_usuario);

            if($auser ne $user){

                print {$out} $linea_usuario, “\n”;

            }

        }

    close $out;

 return 1;

}

De igual manera recibimos el username que queremos eliminar como argumento. Abrimos el archivo .htpasswd y guardamos todo el contenido en el array @usuarios, después volvemos a abrir nuestro archivo pero ahora vamos a sustituir todo el contenido. Hacemos una iteración a través de nuestro array y escribimos en el archivo todas las líneas excepto aquellas donde el username sea el que queremos eliminar.

Listo, a partir de ese momento el usuario ya no podrá tener acceso a nuestra página protegida. Ahora vamos a crear la subrutina encargada de hacer las notificaciones de error:

sub procesar_error {

        # sends notification that an error has occured

        my $err_str = shift;

        my $action = shift;

        my $kill = shift;

        my $req_action = shift;

        my $message = “El siguiente error fue encontrado al intentar hacer la $action:”;

        $message .= “\n\t$err_str\n\n\n”;

        $message .= “Información del Usuario\n”;

        $message .= “\tUsername: ” . param(”username”) . “\n”;

        $message .= “\tEmail: ” . param(”payer_email”) . “\n”;

        $message .= “\tNúmero de Suscripción: ” . param(”subscr_id”) . “\n”;

        $message .= “\tTipo de Transacción: ” . param(”txn_type”) . “\n”;

        my $subject = “Error de Suscripción”;

        if ($req_action) {

                $subject .= ” – Necesita una acción”;

        } else {

                $subject .= ” – No se necesita realizar nada”;

        }

        # if an email is not specified write to error_log only

        if (($ADMIN_EMAIL) && ($SENDMAIL_PATH)) {

             if (!open(SENDMAIL, “|$SENDMAIL_PATH -t”)) {

                    carp “Unable to open sendmail pipe.”;

            }

             print SENDMAIL “To: $ADMIN_EMAIL\n”;

            print SENDMAIL “From: $ADMIN_EMAIL\n”;

            print SENDMAIL “Subject: $subject\n”;

            print SENDMAIL “Content-type: text/plain\n\n”;

            print SENDMAIL “$message”;

             if (!close(SENDMAIL)) {

                carp “Unable to close sendmail pipe.”;

            }

        }

       # put it into the error log

        if ($kill) {

                # IPN will retry

                respuesta(0);

                croak $message;

        } else {

                carp $message;

        }

}

 La subrutina actúa de acuerdo a los siguientes argumentos recibidos:

 

        my $err_str = shift;

        my $action = shift;

        my $kill = shift;

        my $req_action = shift;

 
El primero es la descripción del error, sigue la acción en la cual se encontró el error, después viene $kill que indica si debe de terminarse en ese momento el CGI y después viene si se necesita alguna acción de parte de uno.

Se crea un reporte y se manda a la dirección de correo configurada al principio del CGI.

Finalmente viene la subrutina que va a dar la respuesta final de nuestro script, al cual llamamos respuesta():

sub respuesta {

        # handle the http reponse

        my $is_success = shift;

        if ($is_success) {

                print header(-status=>(’204 No Content’));

        }

        else {

                print header(-status=>(’500 Internal Server Error’));

        }

}

Si vemos, en caso de que haya algún error el script va a regresar un error 500 usando el http-status, de lo contrario un código 204. Esto es muy importante, pues PayPal seguirá mandando la notificación hasta que el script regrese un código exitoso. Eso es todo, nuestro script está completo y listo para utilizarse, ahora todo lo que nos falta es crear el botón de compra.

Con nuestro script de IPN ya tenemos todo listo para empezar a vender nuestras membrecías. Ahora necesitamos hacer el botón de compra. El botón de compra de PayPal es más bien un formulario por medio del cual llamamos a PayPal con todos los argumentos que definen el tipo de compra que van a realizar nuestros usuarios.

Hacer los botones es sumamente sencillo usando la fábrica de botones de PayPal. Lo que vamos a hacer es entrar a nuestra cuenta de PayPal y ahí en la barra de botones de arriba vamos a cliquear sobre Merchant Tools.

Ahí debes de buscar la liga que dice Subscriptions & Recurring Payments bajo el apartado Key Features. Se te va a mostrar la fábrica de botones. Ahí podemos poner todas las características de nuestra membrecía, el nombre, la descripción, el término de la misma, ya sea en días, meses o años, etc.

Es muy importante que al crear tu botón cheques que tengas activada la opción Subscriptions Password Management para que PayPal se encargue de la administración de tus usuarios.

3.JPG

Una vez que hayas creado el botón copia el código que fue generado de manera automática y ponlo en tu página de suscripción.

Haciendo Pruebas

Es muy sencillo realizar pruebas para ver que todo funcione de manera correcta.

Lo que puedes hacer es crear un membrecía que cueste $0.01 y que tenga una duración de un día. Entonces realiza la compra de la membrecía como si fueras un cliente. Esto te va a servir para checar que los usuarios se están dando de alta automáticamente y aparte al día siguiente podrás ver si realmente se dio de baja el usuario.

Ya después de hacer las pruebas necesarias y estar seguro que todo funciona bien, entonces ya puedes poner a la venta tus membrecías.

Como en todo trabajo que involucre inversión, les recomiendo hacer todas las pruebas de control de este script y así se aseguran no tener futuros malos momentos. También pueden descargar el script completo desde:

http://perlenespanol.baboonsoftware.com/tutoriales/misc/ipn_paypal.zip

 

 

 

 

 

 

 

 

 

 

 

 

 

Añadir este post a:  

July 26th, 2007 Posted by javicale | Post ECC | one comment

1 Comment »

  1. [...] ellos, la gente de la Técnica, van un poco mas allá. Ahora nos proponen utilizar PayPal para vender membresias y yo diría cualquier otra cosa que se les pegue la gana. Si les sobra un [...]

    Pingback by De la vida y algo mas…. :: Loja en YouTube :: July :: 2007 | July 29, 2007

Leave a comment

You must be logged in to post a comment.