pay_form_url = ctx.opac_root _ '/payflow/pay_form';
END;
%]
+
+[% IF ctx.payflow_hosted_ctx.pay_result_code %]
+ <!-- Previous payment attempt was rejected by PP -->
+ <div style="background-color:white; width:100%; text-align: center; padding:10px;">
+ [% INCLUDE 'opac/payflow/errors.tt2' %]
+ </div>
+[% END %]
+
<form action="[% pay_form_url %]" method="GET" style="background:#fff">
[% IF ctx.fines.circulation.size > 0 %]
<div id='myopac_circ_trans_div'>
<td>[% l("Date Returned") %]</td>
<td>[% l("Balance Owed") %]</td>
<td nowrap="nowrap" style="white-space:nowrap;">
- <input id="pay_fines_box1" checked="checked"
+ <input id="pay_fines_box1"
+ [% IF NOT ctx.selected_xacts.0 %]checked="checked"[% END %]
type="checkbox" onclick="select_all_checkboxes('xact', this.checked)"
title="[% l('Click to (un)select all fines') %]" />
<label for="pay_fines_box1">[% l('Pay Fines') %]</label>
</strong>
</td>
<td>
- <input type="checkbox" checked="checked"
+ [% checked = NOT ctx.selected_xacts
+ || ctx.selected_xacts.grep(f.xact.id).0 %]
+ <input type="checkbox"
+ [% IF checked %]checked="checked"[% END %]
title="[% l('Pay this fine') %]" name="xact"
value="[% f.xact.id %]" />
</td>
<td width='16%'>[% l("Billing Type") %]</td>
<td width='4%' align="center" nowrap="nowrap"
style="white-space:nowrap;">
- <input id="pay_fines_box2" checked="checked"
+ <input id="pay_fines_box2"
+ [% IF NOT ctx.selected_xacts.0 %]checked="checked"[% END %]
type="checkbox" onclick="select_all_checkboxes('xact_misc', this.checked)"
title="[% l('Click to (un)select all fines') %]" />
<label for="pay_fines_box2">[% l("Pay Fines") %]</label>
</td>
<td>[% f.xact.last_billing_type %]</td>
<td>
- <input type="checkbox" title='[% l("Pay this fine") %]'
- name="xact_misc" value="[% f.xact.id %]"
- checked="checked" />
+ [% checked = NOT ctx.selected_xacts
+ || ctx.selected_xacts.grep(f.xact.id).0 %]
+ <input type="checkbox"
+ [% IF checked %]checked="checked"[% END %]
+ title='[% l("Pay this fine") %]'
+ name="xact_misc" value="[% f.xact.id %]"/>
</td>
</tr>
[% END %]
non-refundable items, visit
<a href="http://kcls.org/faq/borrowing/#faq_1766">
http://kcls.org/faq/borrowing/#faq_1766
- </a><br /><br />
- This site uses VeriSign SSL encryption to ensure your
- privacy.
+ </a><br/>
</td>
</tr>
-<div class="payment-error">
+<div class="payflow-error-container">
+
+<span>There was a problem processing the credit card payment:</span>
+<br/>
+<br/>
+
+<div class="payflow-error-text">
[%
# Map PayFlow POST response codes to patron messages.
CASE DEFAULT;
l('An unkown error occurred attempting credit card payment.');
END;
-
%]
</div>
+<br/>
+<span>Click the 'Pay Fines' button to try the payment again.</span>
+</div>
-<div id='cc-form-warning' class='payment-error' style='display:none'>
- <strong>Please enter values for all required fields.</strong>
- <br/>
-</div>
+<form method="POST" action="[% ctx.payflow_hosted_ctx.forms_server %]">
-<form method="POST" id='cc-form'>
+ <input type="hidden" name="SECURETOKEN"
+ value="[% ctx.payflow_hosted_ctx.secure_token %]"/>
- [% FOR xact IN CGI.param('xact') %]
- <input type="hidden" name="xact" value="[% xact | html %]" />
- [% END %]
-
- [% FOR xact IN CGI.param('xact_misc') %]
- <input type="hidden" name="xact_misc" value="[% xact | html %]" />
- [% END %]
+ <input type="hidden" name="SECURETOKENID"
+ value="[% ctx.payflow_hosted_ctx.secure_token_id %]"/>
<table>
- <tbody>
- <tr>
- <td>[% l('First Name *') %]</td>
- <td><input type="text" name="BILLTOFIRSTNAME"
- value="[% ctx.payflow_hosted_ctx.payflow_params.BILLTOFIRSTNAME
- || ctx.user.first_given_name | html %]" /></td>
- </tr>
- <tr>
- <td>[% l('Last Name *') %]</td>
- <td><input type="text" name="BILLTOLASTNAME"
- value="[% ctx.payflow_hosted_ctx.payflow_params.BILLTOLASTNAME
- || ctx.user.family_name | html %]" /></td>
- </tr>
- <tr>
- <td>[% l('Email Address') %]</td>
- <td>
- <input type="text" name="BILLTOEMAIL"
- value="[% ctx.payflow_hosted_ctx.payflow_params.BILLTOEMAIL
- || ctx.user.email | html %]" />
- </td>
- </tr>
- <tr>
- <td colspan='3'><strong>
- [% l('Please use the address that is on your bank/credit card statement.') %]
- </strong></td>
- </tr>
- <tr>
- <td>[% l('Street Address *') %]</td>
- <td><input type="text" name="BILLTOSTREET"
- value="[% ctx.payflow_hosted_ctx.payflow_params.BILLTOSTREET | html %]"/></td>
- </tr>
- <tr>
- <td>[% l('City *')%]</td>
- <td><input type="text" name="BILLTOCITY"
- value="[% ctx.payflow_hosted_ctx.payflow_params.BILLTOCITY
- || ctx.user.billing_address.city | html %]" /></td>
- </tr>
- <tr>
- <td>[% l('State or Province *') %]</td>
- <td><input type="text" name="BILLTOSTATE"
- value="[% ctx.payflow_hosted_ctx.payflow_params.BILLTOSTATE
- || ctx.user.billing_address.state | html %]" /></td>
- </tr>
- <tr>
- <td>[% l('ZIP or Postal Code *') %]</td>
- <td><input type="text" name="BILLTOZIP"
- value="[% ctx.payflow_hosted_ctx.payflow_params.BILLTOZIP
- || ctx.user.billing_address.post_code | html %]" /></td>
- </tr>
- <tr>
- <td colspan='2' align="center">
- <input type="submit" value="[% l('Next') %]"
- onclick='return check_cc_params()'/>
- <a href="[% mkurl(ctx.opac_root _ '/biblio/main_fines', {}, 1) %]">
- [% l('Cancel') %]
- </a>
- </td>
- </tr>
- </tbody>
+ <tr>
+ <input type="submit" value="[% l('Pay') %]"/>
+ <a href="[% mkurl(ctx.opac_root _ '/biblio/main_fines', {}, 1) %]">
+ [% l('Cancel') %]
+ </a>
+ </td>
+ </tr>
</table>
</form>
-<script>
- //var post_regex = new RegExp(/^\d{5}(?:[-\s]\d{4})?$/);
- var fields = ['ZIP', 'STATE', 'CITY', 'STREET', 'FIRSTNAME', 'LASTNAME'];
-
- function check_cc_params() {
- var form = document.getElementById('cc-form');
- var msg = document.getElementById('cc-form-warning');
- msg.style.display = 'none';
-
- var valid = true;
- for (var i = 0; i < fields.length; i++) {
- var fdom = form['BILLTO' + fields[i]];
- if (fdom.value) {
- fdom.className = '';
- } else {
- fdom.className = 'cc-form-invalid-field';
- valid = false;
- msg.style.display = 'block';
- }
- }
-
- return valid;
- }
-</script>
-
-
+++ /dev/null
-<table>
- <tbody>
- <tr>
- <td>
- <!-- paypal CC payment iframe -->
-
- [% IF ctx.payflow_hosted_error %]
- <strong>
- An error occurred communicating with PayPal.
- Unable to process payment at this time.
- </strong>
- [% STOP %]
- [% END %]
-
- [%
- token = ctx.payflow_hosted_ctx.secure_token | uri;
- token_id = ctx.payflow_hosted_ctx.secure_token_id | uri;
- iframe_url = ctx.payflow_hosted_ctx.hosted_server _
- '?SECURETOKEN=' _ token _ '&SECURETOKENID=' _ token_id;
- IF ctx.payflow_hosted_ctx.test_mode;
- iframe_url = iframe_url _ '&MODE=TEST';
- END;
- %]
- <style>
- #pp-iframe { width: 600px; height: 650px ; scroll: auto}
- </style>
- <iframe id='pp-iframe' src="[% iframe_url %]"> </iframe>
- </td>
- </tr>
- </tbody>
-</table>
-
<style>
#pay-form-container {
background: #fff;
- width: 98%;
- padding: 5px;
+ padding: 10px;
}
- #pay-form-div {
- float:left;
- }
- #pay-xacts-div {
- float:left;
- margin-left: 20px;
+
+ #paypal-form {
+ font-size: 130%;
}
- .cc-form-invalid-field {
- color: black;
- background-color: red;
+
+ #paypal-cancel-div {
+ font-size: 120%;
}
+
+ .myopac_payments_table thead th:first-child { width: auto; }
+ .myopac_payments_table td { padding: 10px }
</style>
<div id="pay-form-container">
-
- <div>
- <h2>[% l('KCLS only accepts Visa or MasterCard') %]</h2>
- <br/>
- <strong>[% l('Billing Information') %]</strong>
- </div>
- <div class="clear-both"></div>
+ <h2>[% l('KCLS only accepts Visa or MasterCard') %]</h2>
+ <br/>
<div id='pay-form-div'>
- [% IF ctx.payflow_hosted_ctx.secure_token_id
- AND NOT ctx.payflow_hosted_ctx.pay_result_code %]
-
- <!-- We have a new secure token. Display the PayPal iframe -->
- [% INCLUDE 'opac/payflow/form2.tt2' %]
+ [% IF ctx.payflow_hosted_ctx.init_error %]
+ <div class="payment-error">
+ [% l('Error initializing credit card payments. Unable to make payments at this time.') %]
+ </div>
[% ELSE %]
+ <form id='paypal-form' method="POST" action="[% ctx.payflow_hosted_ctx.forms_server %]">
+ <input type="hidden" name="SECURETOKEN"
+ value="[% ctx.payflow_hosted_ctx.secure_token %]"/>
- [% IF ctx.payflow_hosted_ctx.pay_result_code %]
- <!-- Previous payment attempt was rejected by PP -->
- [% INCLUDE 'opac/payflow/errors.tt2' %]
- [% ELSIF ctx.payflow_hosted_ctx.init_error %]
- <div class="payment-error">
- [% l('Error initializing credit card payments. Unable to make payments at this time.') %]
- </div>
- [% END %]
-
- <!-- before we talk to paypal, collect address, etc. info from patron -->
- [% INCLUDE 'opac/payflow/form1.tt2' %]
+ <input type="hidden" name="SECURETOKENID"
+ value="[% ctx.payflow_hosted_ctx.secure_token_id %]"/>
+ <input type="submit" value="[% l('Pay') %]"/>
+ </form>
[% END %]
</div>
+
+ <br/>
+ <div id='paypal-cancel-div'>
+ Click
+ <i><b>
+ <a href="[% mkurl(ctx.opac_root _ '/biblio/main_fines', {}, 1) %]">
+ [% l('Cancel') %]
+ </a>
+ </b></i>
+ to go back and change your selection.
+ </div>
+
<div id='pay-xacts-div'>
[% INCLUDE "opac/parts/myopac/payment_xacts.tt2" %]
- <br />
- <span>
- Click
- <strong>
- <a href="[% mkurl(ctx.opac_root _ '/biblio/main_fines', {}, 1) %]">
- [% l('Cancel') %]
- </a>
- </strong>
- to go back and change your selection.
- </span>
- </div>
<div class="clear-both"></div>
<br/>
--- /dev/null
+<b>Payflow Silent POST Placeholder Page</b>
return $self->load_sms_cn if $skip_sms_auth;
}
+ # Payflow silent post responses do not require a login,
+ # because they use a secondary secure token that acts
+ # as an auth token proxy.
+ return $self->load_myopac_payflow_silent_post if $path =~ m|opac/payflow/silent_post|;
+
# ----------------------------------------------------------------
# Everything below here requires authentication
# ----------------------------------------------------------------
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_pay_response if $path =~ m|opac/myopac/pay_response|;
return $self->load_myopac_main if $path =~ m|opac/myopac/main|;
return $self->load_myopac_receipt_email if $path =~ m|opac/myopac/receipt_email|;
return $self->load_myopac_receipt_print if $path =~ m|opac/myopac/receipt_print|;
# PayflowHosted E-Com pages.
return $self->load_myopac_payflow_form if $path =~ m|opac/payflow/pay_form|;
- return $self->load_myopac_payflow_response if $path =~ m|opac/payflow/pay_response|;
return $self->load_myopac_payflow_receipt if $path =~ m|opac/payflow/pay_receipt|;
#BiblioCommons E-Commerce Screens
package OpenILS::WWW::EGCatLoader;
use strict; use warnings;
-use Apache2::Const -compile => qw(OK DECLINED FORBIDDEN HTTP_INTERNAL_SERVER_ERROR REDIRECT HTTP_BAD_REQUEST);
+use Apache2::Const -compile => qw(OK DECLINED FORBIDDEN HTTP_INTERNAL_SERVER_ERROR REDIRECT HTTP_BAD_REQUEST HTTP_REQUEST_TIME_OUT);
use OpenSRF::Utils::Logger qw/$logger/;
use OpenILS::Utils::CStoreEditor qw/:funcs/;
use OpenILS::Utils::Fieldmapper;
return Apache2::Const::OK;
}
-# UI for entering billing address, etc. data.
+# UI for showing summary of fines to pay and form that directs
+# patrons to the PP site for payment.
sub load_myopac_payflow_form {
my $self = shift;
- my $token_id = $self->ctx->{page_args}->[0];
- my $tokens;
my $stat = $self->prepare_extended_user_info;
return $stat if $stat;
# If this is a new payment, the transactions will come from GET params.
my $xacts = [$self->cgi->param('xact'), $self->cgi->param('xact_misc')];
- if ($token_id) {
- # We were directed back to the form1 page after a payment attempt
- # at PP was rejected with a non-zero status.
- # Re-display form1 with error info.
-
- my $cache = OpenSRF::Utils::Cache->new('global');
- $tokens = $cache->get_cache($token_id);
-
- if (!$tokens) {
-
- $logger->error("PayflowHosted payment was rejected, but ".
- "we were unable to retrieve the payment context data ".
- "from the cache. Unable to continue payment!");
-
- $self->ctx->{payflow_hosted_ctx} = {error => 1};
- return Apache2::Const::OK;
- }
-
- # After we render this page, this payment context is no longer valid.
- $self->ctx->{payflow_hosted_ctx} = $tokens;
-
- # If this is an existing payment, pull the transactions from
- # the payment context blob.
- $xacts = $tokens->{xacts};
- }
-
$stat = $self->prepare_fines(undef, undef, $xacts);
return $stat if $stat;
-
- if ($self->cgi->param('BILLTOLASTNAME')) {
- # We received form1 POST data from the patron.
- # Request a secure token from PP en route to form 2.
- # TODO: check for reasonable values for all required fields.
- $self->generate_payflow_secure_token($xacts);
- }
-
+ $self->generate_payflow_secure_token($xacts);
return Apache2::Const::OK;
}
return unless $self->payflow_hosted_enabled;
- # Collect all BILLTO* params from form1.
- my %payflow_params =
- map {$_ => $cgi->param($_)}
- grep /^BILLTO/, $cgi->param;
-
- # amount comes from prepare_fines()
- $payflow_params{AMT} = sprintf("%.2f", $ctx->{fines}->{balance_owed});
-
- $payflow_params{COMMENT1} =
- $ctx->{user}->card->barcode if $ctx->{user}->card;
-
# Generate the PayPal secure token.
my $tokens = OpenILS::WWW::EGCatLoader::PayflowHosted::create_xact_token(
+ authtoken => $self->editor->authtoken,
+ user => $ctx->{user},
+ amount => $ctx->{fines}->{balance_owed}, # from prepare_fines()
billing_org => $org,
- response_host => "https://" . $self->ctx->{hostname},
- payflow_params => \%payflow_params
+ response_host => "https://" . $self->ctx->{hostname}
);
- # The payment form needs these when re-rendering values.
- $tokens->{payflow_params} = \%payflow_params;
-
unless ($tokens && $tokens->{secure_token}) {
# Let the template gracefully warn the user.
$ctx->{payflow_hosted_ctx} = {init_error => 1};
$cache->put_cache($tokens->{secure_token_id}, $tokens, 1800);
}
-# Called from 3rd-party credit card processors to POST payment results data.
-# Caller will not have an authentication token.
-# This happens within an iframe.
-# Either we process the PP POST response data and redirect the user to
-# an intermidiate 'Processing...' page, or if that's already happened,
-# create the payment internally, then let the iframe redirect the
-# browser to the receipts page.
-sub load_myopac_payflow_response {
+
+# See if the provided authtoken is still valid. If so, use it.
+# Otherwise, create a temp auth token using open-ils.auth_internal.
+# Returns undef on succcess, server error on failure.
+sub create_tmp_auth {
my $self = shift;
- my $cgi = $self->cgi;
- my $ctx = $self->ctx;
+ my $authtoken = shift;
+ my $user_id = shift;
- my $token_id = $self->ctx->{page_args}->[0];
+ my $e = $self->editor;
- if ($token_id) {
- # Payflow response has already been received.
- # Create the payment internally now.
-
- $logger->info("PayflowHosted creating payment for token: $token_id");
- return $self->payflow_create_payment($token_id);
+ $e->authtoken($authtoken);
+ if ($e->checkauth) { # test token and set $e->requestor
+ $logger->info(
+ "PayflowHosted existing authtoken still valid for $user_id");
+ return undef;
+ }
- } else {
- # Handling PayFlow POST response. Collect data, put
- # it into the cache, then redirect the caller back to
- # this page to finalize processing.
+ $logger->info("PayflowHosted generating temp auth token for $user_id");
+
+ my $evt = $U->simplereq(
+ 'open-ils.auth_internal',
+ 'open-ils.auth_internal.session.create', {
+ user_id => $user_id,
+ login_type => "temp"
+ }
+ );
- $logger->info("PayflowHosted processing POST results");
- return $self->handle_payflow_response;
+ if ($evt && $evt->{payload} &&
+ ($authtoken = $evt->{payload}->{authtoken})) {
+ $e->authtoken($authtoken);
+ $e->checkauth; # sets $e->requestor
+ return undef;
}
+
+ $logger->error("PayflowHosted unable to generate temp auth ".
+ "session for user $user_id to complete credit card payment!");
+
+ return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR;
}
-sub handle_payflow_response {
+
+sub load_myopac_payflow_silent_post {
my $self = shift;
my $cgi = $self->cgi;
my $ctx = $self->ctx;
my $appr_code = $cgi->param('AUTHCODE');
my $token_id = $cgi->param('SECURETOKENID');
my $result = $cgi->param('RESULT');
+ my $authtoken = $cgi->param('USER1');
# Toss the CGI params into a string for easier error logging.
my $log_params = '';
if (!$token_id) {
$logger->error("PayflowHosted processor responsded with success but ".
"failed to return a SECURETOKENID. Cannot complete payment!");
- $ctx->{payflow_hosted_ctx} = {error => 1};
- return Apache2::Const::OK;
+ return Apache2::Const::HTTP_BAD_REQUEST;
}
- my $cache = OpenSRF::Utils::Cache->new('global');
- my $tokens = $cache->get_cache($token_id);
+ my $tokens = $self->load_payflow_tokens($token_id);
if (!$tokens) {
-
$logger->error("PayflowHosted payment succeeded, but no matching ".
"transaction data found in memcache. Cannot complete payment!");
- $ctx->{payflow_hosted_ctx} = {
- error => 1,
- cc_args => {order_number => $order_number}
- };
-
- return Apache2::Const::OK;
+ # Token data was not found in the cache.
+ # Presumably the cache entry expired.
+ return Apache2::Const::HTTP_REQUEST_TIME_OUT;
}
$tokens->{$_} = $cgi->param($_) for
(qw/RESULT PNREF AVSADDR AVSZIP PROCCVV2/);
$tokens->{pay_result_code} = $result;
- $ctx->{payflow_hosted_ctx} = $tokens;
if ($result eq '0') {
# Payment processed successfully at PP. Track the payment locally.
processor => 'PayflowHosted'
};
- # Redirect to intermediate 'Processing...' page.
- $self->ctx->{refresh} = "1; url=pay_response/$token_id";
- $ctx->{on_processing_page} = 1;
+ # This API is called directly from PP with no session cookie.
+ # Create a new temp auth session for the paying patron via
+ # open-ils.auth_internal.
+ my $stat = $self->create_tmp_auth($authtoken, $tokens->{user});
+ return $stat if $stat;
+
+ return $self->payflow_create_payment($token_id, $tokens);
+ }
+ # Payment failed.
+ if ($result < 0) {
+ $logger->error("PayflowHosted processor returned a".
+ "communication error response code=$result : $respmsg");
} else {
- # Payment failed. Iframe will automatically redirect
- # back to the form1 page to display the message allow
- # for a re-pay attempt.
- if ($result < 0) {
- $logger->error("PayflowHosted processor returned a".
- "communication error response code=$result : $respmsg");
- } else {
- $logger->warn("PayflowHosted processor returned a non-success ".
- "(but recoverable) response code=$result : $respmsg");
- }
+ $logger->warn("PayflowHosted processor returned a non-success ".
+ "(but recoverable) response code=$result : $respmsg");
}
+ # Cache the tokens once again so we can report errors
+ my $cache = OpenSRF::Utils::Cache->new('global');
$cache->put_cache($token_id, $tokens, 1800);
return Apache2::Const::OK;
}
sub payflow_create_payment {
- my ($self, $token_id) = @_;
-
+ my ($self, $token_id, $tokens) = @_;
my $cgi = $self->cgi;
- my $ctx = $self->ctx;
-
my $cache = OpenSRF::Utils::Cache->new('global');
- my $tokens = $cache->get_cache($token_id);
# Must be called before prepare_fines_for_payment();
$self->prepare_fines(undef, undef, $tokens->{xacts});
"open-ils.circ",
"open-ils.circ.money.payment",
$self->editor->authtoken, $args,
- $self->ctx->{user}->last_xact_id
+ $self->editor->requestor->last_xact_id
);
- $self->ctx->{payment_response} = $resp;
- $self->ctx->{token_id} = $token_id;
-
if ($resp->{textcode}) {
- $logger->error("PayflowHosted CC internal payment tracking failed");
- } else {
- $logger->info("PayflowHosted CC internal payment tracking succeeded");
- $logger->info("PayflowHosted created payments: ".Dumper($resp->{payments}));
- $tokens->{payments} = $resp->{payments};
- }
+ $logger->error("PayflowHosted CC internal payment tracking ".
+ "failed with event code " . $resp->{textcode});
+ # Tell PP to void the payment.
+ return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR;
+ }
- $ctx->{payflow_hosted_ctx} = $tokens;
+ $logger->info("PayflowHosted CC internal payment tracking succeeded");
+ $logger->info("PayflowHosted created payments: ".Dumper($resp->{payments}));
+ $tokens->{payments} = $resp->{payments};
- # Cache the payment info so we can generate a receipt on the receipts
- # page, but only cache it for a minute so the token can expire.
- $cache->put_cache($token_id, $tokens, 60);
+ # Cache the payment info to generate a receipt on the receipts page.
+ $cache->put_cache($token_id, $tokens, 1800);
return Apache2::Const::OK;
}
my $token_id = $self->ctx->{page_args}->[0];
return Apache2::Const::HTTP_BAD_REQUEST unless $token_id;
- my $cache = OpenSRF::Utils::Cache->new('global');
- my $tokens = $cache->get_cache($token_id);
+ my $tokens = $self->load_payflow_tokens($token_id);
# this page is loaded immediately after the token is created.
# if the cached data is not there, it's because of an invalid
);
$self->ctx->{payflow_hosted_ctx} = $tokens;
-
- # NOTE: not deleting the cache data since it's set to expire
- # within 60 seconds above.
-
return Apache2::Const::OK;
}
sub load_myopac_main {
my $self = shift;
+ my $token_id = $self->ctx->{page_args}->[0];
my $limit = $self->cgi->param('limit') || 0;
my $offset = $self->cgi->param('offset') || 0;
+
$self->ctx->{search_ou} = $self->_get_search_lib();
$self->ctx->{user}->notes(
$self->editor->search_actor_usr_note({
# determines which payment form page the user is directed to.
$self->ctx->{using_payflow} = $self->payflow_hosted_is_default();
+ if ($self->ctx->{using_payflow} && $token_id) {
+ # If we have a token_id, it means a payment attempt failed.
+ # Load the cached token data so the template can decide what
+ # to do next.
+ my $tokens = $self->load_payflow_tokens($token_id);
+
+ if ($tokens) {
+ # Select the transactions in the transaction list that were
+ # used for the failed payment attempt.
+ $self->ctx->{selected_xacts} = $tokens->{xacts};
+
+ } else {
+
+ $logger->error("PayflowHosted payment failed, but we were ".
+ "unable to retrieve the payment context data from the ".
+ "cache. This may be due to the patron taking too long to ".
+ "complete the payment. Unable to resume payment!");
+
+ $self->ctx->{payflow_hosted_ctx} = {error => 1};
+ }
+ }
+
return $self->prepare_fines($limit, $offset) || Apache2::Const::OK;
}
+sub load_payflow_tokens {
+ my ($self, $token_id) = @_;
+
+ $logger->info(
+ "PayflowHosted loading cached payment info for token ID $token_id");
+
+ my $cache = OpenSRF::Utils::Cache->new('global');
+ my $tokens = $cache->get_cache($token_id);
+
+ return $self->ctx->{payflow_hosted_ctx} = $tokens;
+}
+
sub load_myopac_update_email {
my $self = shift;
my $e = $self->editor;
use OpenSRF::Utils::Logger qw/$logger/;
my $U = 'OpenILS::Application::AppUtils';
-my $test_server = 'https://pilot-payflowpro.paypal.com';
-my $live_server = 'https://payflowpro.paypal.com';
+# API servers
+my $live_api_server = 'https://payflowpro.paypal.com';
+my $test_api_server = 'https://pilot-payflowpro.paypal.com';
-# Hosted Pages server. This is the same for test or live mode.
-my $hosted_server = 'https://payflowlink.paypal.com';
+# Hosted Pages servers
+my $live_forms_server = 'https://payflowlink.paypal.com';
+my $test_forms_server = 'https://pilot-payflowlink.paypal.com';
# Creates a transaction token so the calling code can send the user
# to the hosted pages site.
my %settings = get_settings($params{billing_org});
return undef unless %settings;
- my %pf_params = %{$params{payflow_params}};
-
# Per-transaction unique token
(my $tokenid = create_uuid_as_string(UUID_V4)) =~ s/-//g;
+ my %pf_params;
$pf_params{PARTNER} = $settings{partner};
$pf_params{VENDOR} = $settings{vendor};
$pf_params{TRXTYPE} = 'S'; # sale
- $pf_params{TEMPLATE} = 'MINLAYOUT'; # or MOBILE (AKA "Layout C")
$pf_params{URLMETHOD} = 'POST';
+ $pf_params{TEMPLATE} = 'TEMPLATEA'; # TODO: just for testing
+ $pf_params{AMT} = sprintf("%.2f", $params{amount});
+ $pf_params{USER1} = $params{authtoken};
$pf_params{SECURETOKENID} = $tokenid;
$pf_params{CREATESECURETOKEN} = 'Y';
+ my $user = $params{user};
+
+ $pf_params{COMMENT1} = $user->card->barcode if $user->card;
+ $pf_params{BILLTOFIRSTNAME} = $user->first_given_name;
+ $pf_params{BILLTOLASTNAME} = $user->family_name;
+ $pf_params{BILLTOEMAIL} = $user->email;
+ $pf_params{BILLTOPHONE} = $user->day_phone;
+
+ if (my $addr = $user->billing_address) {
+ $pf_params{BILLTOSTREET} = $addr->street1;
+ $pf_params{BILLTOSTREE2} = $addr->street2;
+ $pf_params{BILLTOCITY} = $addr->city;
+ $pf_params{BILLTOSTATE} = $addr->state;
+ $pf_params{BILLTOZIP} = $addr->post_code;
+ }
+
if ($settings{autohosts}) {
# Tell PP to send POST response data to this host,
# regardless of what's configured within PayPal.
my $host = $params{response_host};
- $pf_params{RETURNURL} = "$host/eg/opac/payflow/pay_response";
$pf_params{CANCELURL} = "$host/eg/opac/biblio/main_fines";
- $pf_params{ERRORURL} = $pf_params{RETURNURL};
+ $pf_params{RETURNURL} = "$host/eg/opac/payflow/pay_receipt/$tokenid";
+ $pf_params{ERRORURL} = "$host/eg/opac/biblio/main_fines/$tokenid";
+ $pf_params{SILENTPOSTURL} = "$host/eg/opac/payflow/silent_post";
}
- my $server = $settings{testmode} ? $test_server : $live_server;
+ my $api_server = $live_api_server;
+ my $forms_server = $live_forms_server;
+ if ($settings{testmode}) {
+ $api_server = $test_api_server;
+ $forms_server = $test_forms_server;
+ }
# Log the request to be sent, minus the user and password values.
- $logger->info("PayflowHosted sending to server $server: ".
+ $logger->info("PayflowHosted sending to server $api_server: ".
encode_params(%pf_params));
# Now that we've logged the params, add the user and password
$pf_params{USER} = $settings{login},
$pf_params{PWD} = $settings{password},
- my $req = HTTP::Request->new(POST => $server);
+ my $req = HTTP::Request->new(POST => $api_server);
$req->header('content-type' => 'text/namevalue');
$req->content(encode_params(%pf_params));
return undef;
}
+ # Avoid leaking sensitive data.
+ delete $pf_params{USER};
+ delete $pf_params{PWD};
+
return {
secure_token => $results{SECURETOKEN},
secure_token_id => $results{SECURETOKENID},
test_mode => $settings{testmode},
- hosted_server => $hosted_server
+ forms_server => $forms_server,
+ payflow_params => \%pf_params
};
}
padding: 10px; border: 1px solid [% css_colors.accent_medium_dark %];
}
+.payflow-error-container {
+ padding: 10px; border: 1px solid [% css_colors.accent_medium_dark %];
+}
+
+.payflow-error-text {
+ font-weight: bold; color: [% css_colors.text_alert %];
+}
+
.payment-processing {
font-weight: bold;
color: [% css_colors.text_greatnews %];
padding: 10px; border: 1px solid #888;
}
+.payflow-error-container {
+ padding: 10px; border: 1px solid #888;
+}
+
+.payflow-error-text {
+ font-weight: bold; color: red;
+}
+
.payment-processing {
font-weight: bold; color: green;
font-size: 120%;