NAME

Catalyst::Model::PayPal::IPN - Handle Instant Payment Notifications and PayPal Button Generation

VERSION

This document describes Catalyst::Model::PayPal::IPN version 0.04

SYNOPSIS

lib/MyApp/Model/Paypal/IPN.pm

package MyApp::Model::Paypal::IPN;

use strict;
use warnings;
use parent 'Catalyst::Model::PayPal::IPN';

1;

myapp.yml

paypal:
    cert_id: 3TFC4UDJER95J
    page_style: MyApp
    no_note: 1
    no_shipping: 1
    lc: GB
    bn: PP-BuyNowBF

Model::Paypal::IPN:
    debug_mode: 1
    encrypt_mode: 0
    business_email: ghenry_1188297224_biz@suretecsystems.com
    currency_code: GBP
    cert: /home/ghenry/MyApp/root/auth/paypal_certs/www.myapp.net.crt
    cert_key: /home/ghenry/MyApp/root/auth/paypal_certs/www.myapp.net.key
    paypal_cert: /home/ghenry/MyApp/root/auth/paypal_certs/paypal_sandbox_cert.pem
    completion_action:
        - Subscribe
        - subscribe
        - payment
        - received
    postback_action:
        - Subscribe
        - subscribe
        - payment
        - ipn
    cancellation_action:
        - Subscribe
        - subscribe
        - payment
        - cancelled

MyApp::Controller::Subscribe

=head2 ipn

Handle PayPal IPN stuff

=cut

sub ipn : Path('payment/ipn') {
    my ( $self, $c ) = @_;

    my $ipn = $c->model('Paypal::IPN');

    if ( $ipn->is_completed ) {
        my %ipn_vars = $ipn->buyer_info();
        $c->stash->{ipn_vars} = \%ipn_vars;

        Do stuff here

        # Just so we reply with something, which in turn sends a HTTP Status 200
        # OK, which we need to stop PayPal.
        # We don't get as we don't use a template and RenderView looks for a
        # template, a body or status equal to 3XX
        $c->res->body('ok');
    }
    else {

    # Just so we reply with something, which in turn sends a HTTP Status 200
    # OK, which we need to stop PayPal.
    # We don't get as we don't use a template and RenderView looks for a
    # template, a body or status equal to 3XX
        $c->res->body('not_ok');
        $c->log->debug( $record_payment_result->transmsgtext ) if $c->debug;
        $c->log->debug( $ipn->error ) if $ipn->error && $c->debug;
    }
}

=head2 cancelled

Cancelled Payment

=cut

sub cancelled : Path('payment/cancelled') {
    my ( $self, $c ) = @_;

    Do stuff on cancel

    $c->stash->{template} = 'user/subscribe/cancelled.tt';
}

=head2 generate_paypal_buttons

=cut

sub generate_paypal_buttons : Private {
    my ( $self, $c ) = @_;

    if ( $c->stash->{all_buttons} ) {
        $c->stash->{subtypes} = [
            $c->model('FTMAdminDB::FTMTariffs')->search(
                {
                    objectname => 'FTM_SUB_TARIFFS',
                    objectitem => 'TARIFFTYPENO',
                    lovlangid  => $langid,
                },
            )
        ];

        for my $tariff ( @{ $c->stash->{subtypes} } ) {
            next if $tariff->tariffid == 1;
            my %data = (
                #cert_id     => $c->config->{paypal}->{cert_id},
                cmd         => '_xclick',
                item_name   => $tariff->itemdesc,
                item_number => $tariff->tariffid,
                amount      => $tariff->peruser,
                page_style  => $c->config->{paypal}->{page_style},
                no_shipping => $c->config->{paypal}->{no_shipping},
                no_note     => $c->config->{paypal}->{no_note},
                'lc'        => $c->config->{paypal}->{lc},
                bn          => $c->config->{paypal}->{bn},
                custom      => $c->req->param('subid'),
            );

            if ( $c->debug ) {
                for my $param ( keys %data ) {
                    $c->log->debug( $param . '=' . $data{$param} );
                }
            }
            $c->stash->{unencrypted_form_data} =
              $c->model('Paypal::IPN')->form_info( \%data );

            my @button_info = (
                $tariff->itemdesc, $tariff->peruser,
                $c->stash->{unencrypted_form_data}
            );
            push @{ $c->stash->{unencrypted_buttons} }, \@button_info;

            #$c->stash->{encrypted_form_data} =
            #  $c->model('Paypal::IPN')->encrypt_form( \%data );

            #my @button_info = (
            #    $tariff->itemdesc, $tariff->peruser,
            #    $c->stash->{encrypted_form_data}
            #);
            #push @{ $c->stash->{encrypted_buttons} }, \@button_info;
        }
    }
}

buttons.tt

<table>
    [% FOREACH button IN unencrypted_buttons %]
        <tr>
            <td><b>[% button.0 %]</b></td>
            <td><b>Price:</b> £[% button.1 %]</td>
            <td class="content">
                <form method="post" action="[% c.model('Paypal::IPN').paypal_gateway %]">
                <input type="hidden" name="cmd" value="_xclick">
                <input type="image" src="https://www.paypal.com/en_US/i/btn/x-click-but23.gif" border="0"
                name="submit" alt="Make payments with PayPal - it's fast, free and secure!">
                <img alt="" border="0" src="https://www.paypal.com/en_GB/i/scr/pixel.gif" width="1" height="1">
        [% FOREACH key IN button.2.keys %]
                <input type="hidden" name="[% key %]" value="[% button.2.$key %]" />
        [% END %]
                </form>
            </td>
        </tr>
    [% END %]
        <tr>
            <td class="content">
                <input type="button" onclick="dojo.widget.byId('profdiag').hide();" value="Close" name="close"/>
            </td>
            <td class="content" colspan="2">
                <a href="#" onclick="javascript:window.open('https://www.paypal.com/uk/cgi-bin/webscr?cmd=xpt/cps/popup/OLCWhatIsPayPal-outside','olcwhatispaypal','toolbar=no,location=no, directories=no, status=no, menubar=no, scrollbars=yes,resizable=yes, width=400, height=350');"><img src="https://www.paypal.com/en_GB/i/bnr/horizontal_solution_PP.gif" border="0"
alt="Solution Graphics"></a>
            </td>
        </tr>
</table>

DESCRIPTION

This model handles all the latest PayPal IPN vars, and provides an easy method for checking that the transaction was successful.

There are also convenience methods for generating encrypted and non-encrypted PayPal forms and buttons.

See Business::PayPal::IPN for more info.

WARNING: this module does not have real tests yet, if you encounter problems please report them via http://rt.cpan.org/ .

INTERFACE

build_paypal_gateway

If debug_mode is on, returns sandbox url, otherwise normal PayPal gateway

is_completed

Calls is_completed from Business::PayPal::IPN

error

Calls error from Business::PayPal::IPN

buyer_info

Returns IPN vars via Business::PayPal::IPN

See https://www.paypal.com/IntegrationCenter/ic_ipn-pdt-variable-reference.html

correlation_info

Returns a hashref of amount, invoice and custom.

form_info

Takes a hashref and returns form data for looping through to create your form.

See SYNOPSIS

encrypt_form

Encrypts form data.

$c->model('Paypal::IPN')->encrypt_form( \%data );

CONFIGURATION AND ENVIRONMENT

The usual techniques for suppling model configuration data in Catalyst apply, but the follow should be present:

Model::Paypal::IPN:
    debug_mode: 1
    encrypt_mode: 0
    business_email: ghenry_1188297224_biz@suretecsystems.com
    currency_code: GBP
    completion_action:
        - Subscribe
        - subscribe
        - payment
        - received
    postback_action:
        - Subscribe
        - subscribe
        - payment
        - ipn
    cancellation_action:
        - Subscribe
        - subscribe
        - payment
        - cancelled

debug_mode switches form url to the PayPal sandbox url. If using encrypted buttons, i.e.

encrypt_mode: 1

then the following will be needed:

cert: /home/ghenry/MyApp/root/auth/paypal_certs/www.myapp.net.crt
cert_key: /home/ghenry/MyApp/root/auth/paypal_certs/www.myapp.net.key
paypal_cert: /home/ghenry/MyApp/root/auth/paypal_certs/paypal_sandbox_cert.pem

Catalyst::Model::PayPal::IPN requires:

DEPENDENCIES

Moose

namespace::clean

Business::PayPal::IPN

Business::PayPal::EWP

BUGS AND LIMITATIONS

No bugs have been reported.

Please report any bugs or feature requests to bug-catalyst-model-paypal-ipn@rt.cpan.org, or through the web interface at http://rt.cpan.org.

AUTHOR

Matt S Trout mst@shadowcatsystems.co.uk

Gavin Henry ghenry@suretecsystems.com

LICENCE AND COPYRIGHT

Copyright (c) 2007, Matt S Trout, mst@shadowcatsystems.co.uk. All rights reserved.

Copyright (c) 2007, Gavin Henry ghenry@suretecsystems.com. All rights reserved.

This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See perlartistic.

DISCLAIMER OF WARRANTY

BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION.

IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.