From bf43887903fafd4ee4477b1f06a4b29b96d2158d Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Thu, 23 Jan 2014 15:18:29 -0500 Subject: [PATCH] Bug 11622 - Add ability to pay fees and fines from OPAC via PayPal This patch adds the ability for a logged in user to pay fines and fees from the OPAC via PayPal. Test Plan: 1) Apply this patch 2) Create a paypal developer account 3) Create two test accounts, a Personal account and a Business account 4) Enable PayPal in Sandbox mode via the system preferences. 5) Enter the business account API credentials into the new system preferences. 6) Create a new patron, add some fines/fees 7) Log in as that patron in the OPAC 8) Choose to pay via PayPal, log in as the sandbox Personal account 9) Complete the transaction 10) Note the fee is now paid --- .../prog/en/modules/admin/preferences/opac.pref | 30 ++ .../en/modules/opac-account-pay-return.tt | 377 +++++++++++++++++++ .../opac-tmpl/bootstrap/en/modules/opac-account.tt | 69 ++++- .../prog/en/modules/opac-account-pay-return.tt | 396 ++++++++++++++++++++ opac/opac-account-pay-paypal-return.pl | 110 ++++++ opac/opac-account-pay.pl | 129 +++++++ opac/opac-account.pl | 9 +- 7 files changed, 1114 insertions(+), 6 deletions(-) create mode 100644 koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-account-pay-return.tt create mode 100644 koha-tmpl/opac-tmpl/prog/en/modules/opac-account-pay-return.tt create mode 100755 opac/opac-account-pay-paypal-return.pl create mode 100755 opac/opac-account-pay.pl diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref index 0c7c507..edbd26f 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref @@ -683,3 +683,33 @@ OPAC: subtype: Subtypes sorting: Sorting location: Location and availability + Payments: + - + - pref: EnablePayPalOpacPayments + default: 1 + choices: + yes: Allow + no: "Don't allow" + - "patrons to make payments from the OPAC via PayPal in" + - pref: PayPalSandboxMode + default: 1 + choices: + yes: "Sandbox" + no: "Production" + - "mode." + - + - "The email address to recieve PayPal payments is " + - pref: PayPalUser + class: long + - + - "The password for the PayPal account to recieve payments is " + - pref: PayPalPwd + class: long + - + - "The signature for the PayPal account to recieve payments is " + - pref: PayPalSignature + class: long + - + - "The patron should see the charge description as " + - pref: PayPalChargeDescription + class: long diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-account-pay-return.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-account-pay-return.tt new file mode 100644 index 0000000..6c78db0 --- /dev/null +++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-account-pay-return.tt @@ -0,0 +1,377 @@ +[% USE Koha %] +[% USE KohaDates %] + +[% INCLUDE 'doc-head-open.inc' %][% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog › Your fines and charges +[% INCLUDE 'doc-head-close.inc' %] +[% BLOCK cssinclude %][% END %] + + + + +[% INCLUDE 'masthead.inc' %] + +
+ + +
+
+
+ +
+
+
+ [% IF error %] +
+

Error: there was an problem processing your payment

+ + [% IF error == "PAYPAL_UNABLE_TO_CONNECT" %] +

Unable to connect to PayPal.

+

Please try again later.

+ [% ELSIF error == "PAYPAL_ERROR_PROCESSING" %] +

Unable to verify payment.

+

Please contact the library to verify your payment.

+ [% END %] +
+ [% ELSIF credit %] +
+

Payment applied: your payment of [% credit.amount_paid %] has been applied to your account

+
+ [% END %] + + Return to fine details +
+
+
+
+
+ +[% INCLUDE 'opac-bottom.inc' %] +[% INCLUDE 'datatables.inc' %] + + + +[% BLOCK jsinclude %][% END %] diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-account.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-account.tt index 03fa58e..b2d0039 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-account.tt +++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-account.tt @@ -1,5 +1,6 @@ [% USE Koha %] [% USE KohaDates %] +[% SET ENABLE_OPAC_PAYMENTS = Koha.Preference('EnablePayPalOpacPayments') %] [% INCLUDE 'doc-head-open.inc' %][% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog › Your fines and charges [% INCLUDE 'doc-head-close.inc' %] @@ -25,12 +26,29 @@
+ + [% IF message %] +
+ [% IF message == 'valid_payment' %] +

Your payment of $[% message_value %] has been processed sucessfully!

+ [% ELSIF message == 'duplicate_payment' %] +

A payment with the transaction id [% message_value %] has already been posted to an account.

+

Please contact a librarian for details.

+ [% ELSIF message == 'invalid_payment' %] +

The transaction id [% message_value %] for this payment is invalid.

+

Please contact a librarian for details.

+ [% END %] +
+ [% END %] +

Fines and charges

[% IF ( ACCOUNT_LINES ) %] +
+ [% IF ENABLE_OPAC_PAYMENTS %][% END %] @@ -40,7 +58,12 @@ - + [%- IF ENABLE_OPAC_PAYMENTS -%] + [%- SET COLSPAN = 4 -%] + [%- ELSE -%] + [%- SET COLSPAN = 3 -%] + [%- END -%] + @@ -48,6 +71,13 @@ [% FOREACH ACCOUNT_LINE IN ACCOUNT_LINES %] [% IF ( ACCOUNT_LINE.odd ) %][% ELSE %][% END %] + [% IF ENABLE_OPAC_PAYMENTS %] + + [% END %]
 Date Description Fine amount
Total dueTotal due [% total %]
+ [% IF ACCOUNT_LINE.amountoutstanding > 0 %] + + [% END %] + [% ACCOUNT_LINE.date | $KohaDates %] [% SWITCH ACCOUNT_LINE.accounttype %] @@ -81,6 +111,33 @@
+ + [% IF ENABLE_OPAC_PAYMENTS %] +
+ Pay selected fines and charges +

Payment method

+
+ +
+ + +
+ + +
+
+ [% END %] +
[% ELSE %]

You have no fines or charges

[% END %] @@ -91,4 +148,12 @@
[% INCLUDE 'opac-bottom.inc' %] -[% BLOCK jsinclude %][% END %] +[% BLOCK jsinclude %] + +[% END %] diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-account-pay-return.tt b/koha-tmpl/opac-tmpl/prog/en/modules/opac-account-pay-return.tt new file mode 100644 index 0000000..8fc3edc --- /dev/null +++ b/koha-tmpl/opac-tmpl/prog/en/modules/opac-account-pay-return.tt @@ -0,0 +1,396 @@ +[% SET accountview = 1 %] + +[% USE Koha %] +[% USE KohaDates %] +[% USE Currency %] + +[% INCLUDE 'doc-head-open.inc' %][% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog › Your fines and charges +[% INCLUDE 'doc-head-close.inc' %] + + +
+
+ [% INCLUDE 'masthead.inc' %] +
+
+
+
+

[% borrower.firstname %] [% borrower.surname %]'s account ⇢ Fines and charges

+ + [% IF error %] +
+

Error: there was an problem processing your payment

+ + [% IF error == "PAYPAL_UNABLE_TO_CONNECT" %] +

Unable to connect to PayPal.

+

Please try again later.

+ [% ELSIF error == "PAYPAL_ERROR_PROCESSING" %] +

Unable to verify payment.

+

Please contact the library to verify your payment.

+ [% END %] +
+ [% ELSIF credit %] +
+

Payment applied: your payment of [% credit.amount_paid %] has been applied to your account

+
+ [% END %] + + Return to fine details +
+
+
+
+ +
+
+ [% INCLUDE 'navigation.inc' IsPatronPage=1 %] +
+
+
+[% INCLUDE 'opac-bottom.inc' %] + +[% INCLUDE 'datatables.inc' %] +[% INCLUDE 'browser-strings.inc' %] + + + +[% BLOCK jsinclude %][% END %] + +[% BLOCK format_data %] + [% FOREACH key IN data.result_source.columns %] + [% IF key.match('^amount') %] + "[% key %]": "[% data.$key FILTER $Currency %]", + "[% key %]_unformatted": "[% data.$key %]", + [% ELSIF key.match('_on$') %] + "[% key %]": "[% data.$key | $KohaDates %]", + "[% key %]_unformatted": "[% data.$key %]", + [% ELSE %] + "[% key %]": "[% data.$key %]", + [% END %] + [% END %] +[% END %] diff --git a/opac/opac-account-pay-paypal-return.pl b/opac/opac-account-pay-paypal-return.pl new file mode 100755 index 0000000..42eb34b --- /dev/null +++ b/opac/opac-account-pay-paypal-return.pl @@ -0,0 +1,110 @@ +#!/usr/bin/perl + +# Copyright Katipo Communications 2002 +# Copyright Biblibre 2007,2010 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; +use utf8; + +use CGI; +use HTTP::Request::Common; +use LWP::UserAgent; +use URL::Encode qw(url_params_mixed); + +use C4::Auth; +use C4::Output; +use C4::Accounts; +use C4::Members; +use Koha::Database; + +my $cgi = new CGI; + +unless ( C4::Context->preference('EnablePayPalOpacPayments') ) { + print $cgi->redirect("/cgi-bin/koha/errors/404.pl"); + exit; +} + +my ( $template, $borrowernumber, $cookie ) = get_template_and_user( + { + template_name => "opac-account-pay-return.tt", + query => $cgi, + type => "opac", + authnotrequired => 0, + flagsrequired => { borrow => 1 }, + debug => 1, + } +); + +my $token = $cgi->param('token'); +my $payer_id = $cgi->param('PayerID'); +my $amount = $cgi->param('amount'); +my @accountlines = $cgi->param('accountlines'); + +my $ua = LWP::UserAgent->new; + +my $url = + C4::Context->preference('PayPalSandboxMode') + ? 'https://api-3t.sandbox.paypal.com/nvp' + : 'https://api-3t.paypal.com/nvp'; + +my $nvp_params = { + 'USER' => C4::Context->preference('PayPalUser'), + 'PWD' => C4::Context->preference('PayPalPwd'), + 'SIGNATURE' => C4::Context->preference('PayPalSignature'), + + # API Version and Operation + 'METHOD' => 'DoExpressCheckoutPayment', + 'VERSION' => '82.0', + + # API specifics for DoExpressCheckout + 'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale', + 'PAYERID' => $payer_id, + 'TOKEN' => $token, + 'PAYMENTREQUEST_0_AMT' => $amount, +}; + +my $response = $ua->request( POST $url, $nvp_params ); + +if ( $response->is_success ) { + my $params = url_params_mixed( $response->decoded_content ); + + if ( $params->{ACK} eq "Success" ) { + $amount = $params->{PAYMENTINFO_0_AMT}; + + my $accountlines_rs = Koha::Database->new()->schema()->resultset('Accountline'); + foreach my $accountlines_id ( @accountlines ) { + my $accountline = $accountlines_rs->find( $accountlines_id ); + makepayment( $accountlines_id, $borrowernumber, undef, $accountline->amountoutstanding, undef, undef, 'PayPal' ); + } + } + else { + $template->param( error => "PAYPAL_ERROR_PROCESSING" ); + } + +} +else { + $template->param( error => "PAYPAL_UNABLE_TO_CONNECT" ); +} + +$template->param( + borrower => GetMemberDetails($borrowernumber), + accountview => 1 +); + +output_html_with_http_headers( $cgi, $cookie, $template->output ); diff --git a/opac/opac-account-pay.pl b/opac/opac-account-pay.pl new file mode 100755 index 0000000..bc67d1d --- /dev/null +++ b/opac/opac-account-pay.pl @@ -0,0 +1,129 @@ +#!/usr/bin/perl + +# Copyright Katipo Communications 2002 +# Copyright Biblibre 2007,2010 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use utf8; + +use Modern::Perl; + +use CGI; +use HTTP::Request::Common; +use LWP::UserAgent; +use URL::Encode qw(url_encode url_params_mixed); +use URI; + +use C4::Auth; +use C4::Output; +use C4::Context; +use Koha::Database; + +my $cgi = new CGI; + +unless ( C4::Context->preference('EnablePayPalOpacPayments') ) { + print $cgi->redirect("/cgi-bin/koha/errors/404.pl"); + exit; +} + +my ( $template, $borrowernumber, $cookie ) = get_template_and_user( + { + template_name => "opac-account-pay-return.tt", + query => $cgi, + type => "opac", + authnotrequired => 0, + flagsrequired => { borrow => 1 }, + debug => 1, + } +); + +my $payment_method = $cgi->param('payment_method'); +my @accountlines = $cgi->param('accountline'); + +my $amount_to_pay = + Koha::Database->new()->schema()->resultset('Accountline')->search( { accountlines_id => { -in => \@accountlines } } ) + ->get_column('amountoutstanding')->sum(); +$amount_to_pay = sprintf( "%.2f", $amount_to_pay ); + +my $error = 0; +if ( $payment_method eq 'paypal' ) { + my $ua = LWP::UserAgent->new; + + my $amount = url_encode($amount_to_pay); + + my $url = + C4::Context->preference('PayPalSandboxMode') + ? 'https://api-3t.sandbox.paypal.com/nvp' + : 'https://api-3t.paypal.com/nvp'; + + my $opac_base_url = C4::Context->preference('OPACBaseURL'); + + my $return_url = URI->new( $opac_base_url . "/cgi-bin/koha/opac-account-pay-paypal-return.pl" ); + $return_url->query_form( { amount => $amount, accountlines => \@accountlines } ); + + my $cancel_url = URI->new( $opac_base_url . "/cgi-bin/koha/opac-account.pl" ); + + my $nvp_params = { + 'USER' => C4::Context->preference('PayPalUser'), + 'PWD' => C4::Context->preference('PayPalPwd'), + 'SIGNATURE' => C4::Context->preference('PayPalSignature'), + + # API Version and Operation + 'METHOD' => 'SetExpressCheckout', + 'VERSION' => '82.0', + + # API specifics for SetExpressCheckout + 'NOSHIPPING' => 1, + 'REQCONFIRMSHIPPING' => 0, + 'ALLOWNOTE' => 0, + 'BRANDNAME' => C4::Context->preference('LibraryName'), + 'CANCELURL' => $cancel_url->as_string(), + 'RETURNURL' => $return_url->as_string(), + 'PAYMENTREQUEST_0_AMT' => $amount_to_pay, + 'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale', + 'PAYMENTREQUEST_0_ALLOWEDPAYMENTMETHOD' => 'InstantPaymentOnly', + 'PAYMENTREQUEST_0_DESC' => C4::Context->preference('PayPalChargeDescription'), + }; + + my $response = $ua->request( POST $url, $nvp_params ); + + if ( $response->is_success ) { + my $params = url_params_mixed( $response->decoded_content ); + + if ( $params->{ACK} eq "Success" ) { + my $token = $params->{TOKEN}; + + my $redirect_url = + C4::Context->preference('PayPalSandboxMode') + ? "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=" + : "https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token="; + print $cgi->redirect( $redirect_url . $token ); + + } + else { + $template->param( error => "PAYPAL_ERROR_PROCESSING" ); + $error = 1; + } + + } + else { + $template->param( error => "PAYPAL_UNABLE_TO_CONNECT" ); + $error = 1; + } +} + +output_html_with_http_headers( $cgi, $cookie, $template->output ) if $error; diff --git a/opac/opac-account.pl b/opac/opac-account.pl index e575650..7c70e69 100755 --- a/opac/opac-account.pl +++ b/opac/opac-account.pl @@ -22,7 +22,6 @@ use strict; use CGI qw ( -utf8 ); use C4::Members; -use C4::Circulation; use C4::Auth; use C4::Output; use warnings; @@ -68,10 +67,12 @@ foreach my $row (@$accts) { $num++; } -$template->param ( +$template->param( ACCOUNT_LINES => $accts, - total => sprintf( "%.2f", $total ), - accountview => 1 + total => sprintf( "%.2f", $total ), + accountview => 1, + message => $query->param('message') || q{}, + message_value => $query->param('message_value') || q{}, ); output_html_with_http_headers $query, $cookie, $template->output; -- 1.7.2.5