@@ -, +, @@ 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 --- .../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 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref +++ a/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 --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-account-pay-return.tt +++ a/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 %] --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-account.tt +++ a/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 %] --- a/koha-tmpl/opac-tmpl/prog/en/modules/opac-account-pay-return.tt +++ a/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 %] --- a/opac/opac-account-pay-paypal-return.pl +++ a/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 ); --- a/opac/opac-account-pay.pl +++ a/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; --- a/opac/opac-account.pl +++ a/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; --