From 40883394783ca36c40bf4069d64c3072279d0cd9 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Mon, 21 Nov 2011 15:47:37 -0500 Subject: [PATCH] TPac; credit card payment "Processing..." page To prevent impatient patrons from re-submitting credit card payment request forms, insert a Processing... page between the initial form submission and the actual payment processing. Steps 3-5 are new or modified. 1. User selects transactions to pay 2. User fills in payment form and Submits 3. Payment form data is cached in memcache with a temporary token 4. Processing page is displayed with message about how processing the payment can take time, do not refresh, etc. 5. Page is refreshed via http meta refresh to submit the form using the temp token. The page is not visibly changed, though, since it takes time for the form submission to begin returning data. 6. User is directed to the payment results page. Signed-off-by: Bill Erickson Signed-off-by: Mike Rylander --- .../src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm | 1 + .../lib/OpenILS/WWW/EGCatLoader/Account.pm | 83 ++++++++++++++++++---- Open-ILS/src/templates/opac/myopac/main_pay.tt2 | 2 + .../src/templates/opac/myopac/main_pay_init.tt2 | 15 ++++ .../templates/opac/myopac/main_payment_form.tt2 | 2 +- Open-ILS/web/css/skin/default/opac/style.css | 7 ++ 6 files changed, 94 insertions(+), 16 deletions(-) create mode 100644 Open-ILS/src/templates/opac/myopac/main_pay_init.tt2 diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm index 76b3f63353..14e076032c 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm @@ -144,6 +144,7 @@ sub load { return $self->load_myopac_circs if $path =~ m|opac/myopac/circs|; return $self->load_myopac_payment_form if $path =~ m|opac/myopac/main_payment_form|; return $self->load_myopac_payments if $path =~ m|opac/myopac/main_payments|; + return $self->load_myopac_pay_init if $path =~ m|opac/myopac/main_pay_init|; return $self->load_myopac_pay if $path =~ m|opac/myopac/main_pay|; return $self->load_myopac_main if $path =~ m|opac/myopac/main|; return $self->load_myopac_receipt_email if $path =~ m|opac/myopac/receipt_email|; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm index fddb0edc0b..da6f3b45a9 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm @@ -7,6 +7,8 @@ use OpenILS::Utils::Fieldmapper; use OpenILS::Application::AppUtils; use OpenILS::Event; use OpenSRF::Utils::JSON; +use OpenSRF::Utils::Cache; +use Digest::MD5 qw(md5_hex); use Data::Dumper; $Data::Dumper::Indent = 0; use DateTime; @@ -1167,24 +1169,15 @@ sub load_myopac_payments { return Apache2::Const::OK; } -sub load_myopac_pay { +# 1. caches the form parameters +# 2. loads the credit card payment "Processing..." page +sub load_myopac_pay_init { my $self = shift; - my $r; + my $cache = OpenSRF::Utils::Cache->new('global'); my @payment_xacts = ($self->cgi->param('xact'), $self->cgi->param('xact_misc')); - $logger->info("tpac paying fines for xacts @payment_xacts"); - - $r = $self->prepare_fines(undef, undef, \@payment_xacts) and return $r; - # balance_owed is computed specifically from the fines we're trying - # to pay in this case. - if ($self->ctx->{fines}->{balance_owed} <= 0) { - $self->apache->log->info( - sprintf("Can't pay non-positive balance. xacts selected: (%s)", - join(", ", map(int, $self->cgi->param("xact"), $self->cgi->param('xact_misc')))) - ); - return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR; - } + return $self->generic_redirect unless @payment_xacts; my $cc_args = {"where_process" => 1}; @@ -1194,11 +1187,71 @@ sub load_myopac_pay { billing_zip /); + my $cache_args = { + cc_args => $cc_args, + user => $self->ctx->{user}->id, + xacts => \@payment_xacts + }; + + # generate a temporary cache token and cache the form data + my $token = md5_hex($$ . time() . rand()); + $cache->put_cache($token, $cache_args, 30); + + $logger->info("tpac caching payment info with token $token and xacts [@payment_xacts]"); + + # after we render the processing page, we quickly redirect to submit + # the actual payment. The refresh url contains the payment token. + # It also contains the list of xact IDs, which allows us to clear the + # cache at the earliest possible time while leaving a trace of which + # transactions we were processing, so the UI can bring the user back + # to the payment form w/ the same xacts if the payment fails. + + my $refresh = "1; url=main_pay/$token?xact=" . pop(@payment_xacts); + $refresh .= ";xact=$_" for @payment_xacts; + $self->ctx->{refresh} = $refresh; + + return Apache2::Const::OK; +} + +# retrieve the cached CC payment info and send off for processing +sub load_myopac_pay { + my $self = shift; + my $token = $self->ctx->{page_args}->[0]; + return Apache2::Const::HTTP_BAD_REQUEST unless $token; + + my $cache = OpenSRF::Utils::Cache->new('global'); + my $cache_args = $cache->get_cache($token); + $cache->delete_cache($token); + + # this page is loaded immediately after the token is created. + # if the cached data is not there, it's because of an invalid + # token (or cache failure) and not because of a timeout. + return Apache2::Const::HTTP_BAD_REQUEST unless $cache_args; + + my @payment_xacts = @{$cache_args->{xacts}}; + my $cc_args = $cache_args->{cc_args}; + + # as an added security check, verify the user submitting + # the form is the same as the user whose data was cached + return Apache2::Const::HTTP_BAD_REQUEST unless + $cache_args->{user} == $self->ctx->{user}->id; + + $logger->info("tpac paying fines with token $token and xacts [@payment_xacts]"); + + my $r; + $r = $self->prepare_fines(undef, undef, \@payment_xacts) and return $r; + + # balance_owed is computed specifically from the fines we're paying + if ($self->ctx->{fines}->{balance_owed} <= 0) { + $logger->info("tpac can't pay non-positive balance. xacts selected: [@payment_xacts]"); + return Apache2::Const::HTTP_BAD_REQUEST; + } + my $args = { "cc_args" => $cc_args, "userid" => $self->ctx->{user}->id, "payment_type" => "credit_card_payment", - "payments" => $self->prepare_fines_for_payment # should be safe after self->prepare_fines + "payments" => $self->prepare_fines_for_payment # should be safe after self->prepare_fines }; my $resp = $U->simplereq("open-ils.circ", "open-ils.circ.money.payment", diff --git a/Open-ILS/src/templates/opac/myopac/main_pay.tt2 b/Open-ILS/src/templates/opac/myopac/main_pay.tt2 index 7c3468210f..e02d956511 100644 --- a/Open-ILS/src/templates/opac/myopac/main_pay.tt2 +++ b/Open-ILS/src/templates/opac/myopac/main_pay.tt2 @@ -4,6 +4,7 @@ myopac_page = "main"; myopac_main_page = "pay" %]
+ [% IF ctx.payment_response.textcode %]
@@ -22,6 +23,7 @@ END; retry_url = mkurl(ctx.opac_root _ '/myopac/main_payment_form', url_args, 1); %] +
[% l('Go back') %] [% l('to try again or to cancel this payment attempt.') %]

diff --git a/Open-ILS/src/templates/opac/myopac/main_pay_init.tt2 b/Open-ILS/src/templates/opac/myopac/main_pay_init.tt2 new file mode 100644 index 0000000000..835571070f --- /dev/null +++ b/Open-ILS/src/templates/opac/myopac/main_pay_init.tt2 @@ -0,0 +1,15 @@ +[% PROCESS "opac/parts/header.tt2"; + PROCESS "opac/parts/misc_util.tt2"; + WRAPPER "opac/parts/myopac/base.tt2"; + myopac_page = "main"; + myopac_main_page = "pay" %] +
+ +
+ [% l('Processing...') %]

+ [% l('Processing your payment may take some time.') %]
+ [% l("Please do not Refresh or use your browser's Back button or your credit card may be charged more than once.") %]
+
+ +
+[% END %] diff --git a/Open-ILS/src/templates/opac/myopac/main_payment_form.tt2 b/Open-ILS/src/templates/opac/myopac/main_payment_form.tt2 index cb4d4a177b..3f152b1e37 100644 --- a/Open-ILS/src/templates/opac/myopac/main_payment_form.tt2 +++ b/Open-ILS/src/templates/opac/myopac/main_payment_form.tt2 @@ -16,7 +16,7 @@
[% IF last_chance %]

[% l("Are you sure you are ready to charge [_1] to your credit card?", money(ctx.fines.balance_owed)) %]

-
+ [% FOR k IN CGI.Vars; NEXT UNLESS k; FOR val IN CGI.param(k) %] diff --git a/Open-ILS/web/css/skin/default/opac/style.css b/Open-ILS/web/css/skin/default/opac/style.css index 10dacd9a89..0279eea4d7 100644 --- a/Open-ILS/web/css/skin/default/opac/style.css +++ b/Open-ILS/web/css/skin/default/opac/style.css @@ -960,6 +960,13 @@ div.result_place_hold { padding: 10px; border: 1px solid #888; } +.payment-processing { + font-weight: bold; color: green; + font-size: 120%; + padding: 10px; border: 1px solid #888; + text-align: center; +} + #adv_search_parent { margin-bottom:0px; } -- 2.11.0