Merge commit 'v7.10.17' into 8

Conflicts:
	docs/upgrades/upgrade_7.9.13-7.10.0.pl
	lib/WebGUI.pm
	lib/WebGUI/Asset/Template/TemplateToolkit.pm
	lib/WebGUI/Asset/Wobject/AssetReport.pm
	lib/WebGUI/Asset/Wobject/Thingy.pm
	lib/WebGUI/Form/Captcha.pm
	lib/WebGUI/Macro/AdminBar.pm
	lib/WebGUI/Shop/Cart.pm
	lib/WebGUI/Shop/PayDriver.pm
	lib/WebGUI/Shop/PayDriver/PayPal/ExpressCheckout.pm
	lib/WebGUI/Shop/PayDriver/PayPal/PayPalStd.pm
	lib/WebGUI/Shop/Transaction.pm
	lib/WebGUI/Workflow/Instance.pm
	lib/WebGUI/Workflow/Spectre.pm
	lib/WebGUI/i18n/English/PayDriver.pm
	t/Asset/Asset.t
	t/Asset/AssetExportHtml.t
	t/Asset/AssetLineage.t
	t/Asset/Wobject/Thingy.t
This commit is contained in:
Doug Bell 2011-06-17 20:13:41 -05:00
commit 795d88e7e5
69 changed files with 972 additions and 170 deletions

View file

@ -986,7 +986,7 @@ sub www_checkout {
my $total = $self->calculateTotal;
##Handle rounding errors, and checkout immediately if the amount is 0 since
##at least the ITransact driver won't accept $0 checkout.
if (sprintf('%.2f', $total + $self->calculateShopCreditDeduction($total)) eq '0.00') {
if (sprintf('%.2f', abs($total + $self->calculateShopCreditDeduction($total))) eq '0.00') {
my $transaction = WebGUI::Shop::Transaction->new({session => $session, cart => $self});
$transaction->write;
$transaction->completePurchase('zero', 'success', 'success');
@ -1032,9 +1032,6 @@ sub www_lookupPosUser {
Updates the cart totals, addresses, shipping driver and payment gateway. If requested, and the
cart is ready, calls the www_getCredentials method from the selected payment gateway.
If the cart total, after taxes, shipping, coupons and shop credit is zero, does the checkout
immediately without calling a payment gateway.
Otherwise, returns the user back to the cart.
=cut

View file

@ -129,8 +129,13 @@ around BUILDARGS => sub {
=head2 appendCartVariables ( $var )
Append the subtotal, shipping, tax, and shop credeductions to a set of template
variables.
Append the subtotal, shipping, tax, and shop credit deductions to a set of template
variables. Returns the modified hashreference of variables.
=head3 $var
A hashref. Template variables will be added to it. If $var is not passed, a new
hashref is created, and that is returned.
=cut
@ -148,7 +153,7 @@ sub appendCartVariables {
$var->{inShopCreditAvailable} = $credit->getSum;
$var->{inShopCreditDeduction} = $credit->calculateDeduction($totalPrice);
$var->{totalPrice } = $cart->formatCurrency($totalPrice + $var->{inShopCreditDeduction});
return $self;
return $var;
}
@ -259,10 +264,14 @@ sub displayPaymentError {
my ($self, $transaction) = @_;
my $i18n = WebGUI::International->new($self->session, "PayDriver");
my $output = q{<h1>} . $i18n->get('error processing payment') . q{</h1>}
. q{<p>} . $i18n->get('error processing payment message') . q{</p>}
. q{<p>} . $transaction->get('statusMessage') . q{</p>}
. q{<p><a href="?shop=cart;method=checkout">} . $i18n->get( 'try again' ) . q{</a></p>}
;
. q{<p>} . $i18n->get('error processing payment message') . q{</p>};
if ($transaction) {
$output .= q{<p>} . $transaction->get('statusMessage') . q{</p>};
}
else {
$output .= q{<p>} . $i18n->get('unable to finish transaction') . q{</p>};
}
$output .= q{<p><a href="?shop=cart;method=checkout">} . $i18n->get( 'try again' ) . q{</a></p>};
return $self->session->style->userStyle($output);
}
@ -540,7 +549,7 @@ sub processTransaction {
$transactionProperties->{ cart } = $cart;
$transactionProperties->{ isRecurring } = $cart->requiresRecurringPayment;
$transactionProperties->{ session } = $self->session;
# Create a transaction...
$transaction = WebGUI::Shop::Transaction->new( $transactionProperties );
$transaction->write;

View file

@ -121,7 +121,7 @@ sub processPayment {
my $self = shift;
# Since we'll have to create a transaction before doing the actual tranasction, we let it fail
# initially with a message that it is pending.
# Unless the transaction result with _setPaymentStatus the transaction will fail.
# Unless the transaction result is updated via _setPaymentStatus the transaction will fail.
my $success = $self->{_transactionSuccessful} || 0;
my $id = $self->{_ogoneId} || undef;
@ -129,7 +129,6 @@ sub processPayment {
my $message = $self->{_statusMessage} || 'Waiting for checkout';
return ( $success, $id, $status, $message );
return (0, undef, 1, 'Pending');
}
#-------------------------------------------------------------------

View file

@ -172,7 +172,7 @@ is a hashref, it will be modified in place.
sub payPalForm {
my $self = shift;
my $args = ref $_[0] eq 'HASH' ? shift : {@_};
$args->{VERSION} = '58.0';
$args->{VERSION} = '2.3';
$args->{USER} = $self->user;
$args->{PWD} = $self->password;
$args->{SIGNATURE} = $self->signature;
@ -206,7 +206,6 @@ PayPal API spit back.
sub processPayment {
my ( $self, $transaction ) = @_;
my ( $isSuccess, $gatewayCode, $status, $message );
my $form = $self->payPalForm(
METHOD => 'DoExpressCheckoutPayment',
@ -317,6 +316,7 @@ sub www_sendToPayPal {
if ($params) {
unless ( $params->{ACK} =~ /^Success/ ) {
my $log = sprintf "Paypal error: Request/response below: %s\n%s\n", Dumper($form), Dumper($params);
$log .= $response->request->as_string;
$session->log->error($log);
$error = $i18n->get('internal paypal error');
}

View file

@ -20,6 +20,8 @@ use URI;
use URI::Escape;
use LWP::UserAgent;
use Readonly;
use WebGUI::Shop::Transaction;
Readonly my $I18N => 'PayDriver_PayPalStd';
use Moose;
@ -145,7 +147,9 @@ sub getButton {
# All the API stuff is done in paymentVariables; we'll just turn it into
# hidden form fields here
my $v = $self->paymentVariables;
my $v = $self->paymentVariables;
my $transaction = $self->processTransaction();
$v->{custom} = $transaction->getId;
my $fields = join "\n", map {
WebGUI::Form::hidden( $session, { name => $_, value => $v->{$_} } )
} (keys %$v);
@ -177,6 +181,38 @@ sub getButton {
#-------------------------------------------------------------------
=head2 getPayPalParams
Using the tx form variable, dial up PayPal and ask them for details about the transaction.
Return a hashreference of name/value pairs, along with PAYPAL_TX, the transactionId and
PAYPAL_REQUEST_STATUS, the HTTP code from the response from PayPal.
=cut
sub getPayPalParams {
my $self = shift;
my $session = $self->session;
# instead of relying on what was passed to us.
return $self->{_params} if $self->{_params};
my $tx = $session->form->process('tx');
my %form = (
cmd => '_notify-synch',
tx => $tx,
at => $self->identityToken,
);
my $response = LWP::UserAgent->new->post($self->payPalUrl, \%form);
my ($status, @lines) = split("\n", $response->content);
my %params = map { split /=/ }
map { uri_unescape($_) } @lines;
$params{PAYPAL_REQUEST_STATUS} = $status;
$params{PAYPAL_TX} = $tx;
$self->{_params} = \%params;
return $self->{_params};
}
#-------------------------------------------------------------------
=head2 paymentVariables
Returns a hashref of the payment variables to be used as hidden form fields
@ -225,9 +261,9 @@ sub paymentVariables {
foreach my $item (@{ $cart->getItems}) {
my $n = ++$counter;
$params{"amount_$n"} = $item->getSku->getPrice;
$params{"quantity_$n"} = $item->get('quantity');
$params{"item_name_$n"} = $item->get('configuredTitle');
$params{"item_number_$n"} = $item->get('itemId');
$params{"quantity_$n"} = $item->quantity;
$params{"item_name_$n"} = $item->configuredTitle;
$params{"item_number_$n"} = $item->itemId;
}
return \%params;
@ -258,49 +294,49 @@ passed to us.
=cut
sub processPayment {
my ( $self, $transaction ) = @_;
my $session = $self->session;
my ( $self ) = @_;
# To prevent a spoofed post to this url, we'll get the info from paypal
# instead of relying on what was passed to us.
my $tx = $session->form->process('tx');
my $success = $self->{_transactionSuccessful} || 0;
my $id = $self->{_tx} || undef;
my $status = $self->{_statusCode} || undef;
my $message = $self->{_statusMessage} || 'Waiting for checkout';
my %form = (
cmd => '_notify-synch',
tx => $tx,
at => $self->identityToken,
);
my $response = LWP::UserAgent->new->post($self->payPalUrl, \%form);
my ($status, @lines) = split("\n", $response->content);
my %params = map { split /=/ }
map { uri_unescape($_) } @lines;
return ( $success, $id, $status, $message );
}
if ($status =~ /FAIL/) {
my $message = '<table><tr><th>Field</th><th>Value</th></tr>';
foreach my $key ( keys %params ) {
$message .= "<tr><td>$key</td><td>$params{$key}</td></tr>";
}
$message .= '</table>';
return ( 0, $tx, $status, $message );
}
#-------------------------------------------------------------------
# Make sure the transaction is for this cart to prevent spoofing
my $cartId = $self->getCart->getId;
if ($params{custom} ne $cartId) {
my $user = $session->user;
my $name = $user->username;
my $id = $user->userId;
$session->log->warn("SECURITY WARNING: $name (id: $id) tried to " .
"checkout cart $cartId with PayPal transaction $tx, which " .
"did not match the cart we passed ($params{custom})");
=head2 _setPaymentStatus ( transactionSuccessful, ogoneId, statusCode, statusMessage )
my $i18n = WebGUI::International->new( $session, $I18N );
return ( 0, $tx, 'FAIL', $i18n->get('cart transaction mismatch') );
}
Update the internal status of a payment, so that the next call to processPayment
returns the correct data.
$status = $params{payment_status};
return ( 1, $tx, $status, $status, $status );
} ## end sub processPayment
=head3 transactionSuccessful
A boolean indicating whether or not the payment was successful.
=head3 tx
The PayPal issued transaction ID.
=head3 statusCode
The PayPal issued status code.
=head3 statusMessage
An updates status message
=cut
sub _setPaymentStatus {
my ( $self ) = @_;
$self->{_transactionSuccessful} = shift || 0;
$self->{_tx} = shift || undef;
$self->{_statusCode} = shift || undef;
$self->{_statusMessage} = shift || undef;
}
#-------------------------------------------------------------------
@ -311,11 +347,26 @@ Where paypal comes back to when a transaction has been completed.
=cut
sub www_completeTransaction {
my $self = shift;
my $self = shift;
my $session = $self->session;
my $transaction = $self->processTransaction;
my $params = $self->getPayPalParams;
if ($params->{PAYPAL_REQUEST_STATUS} =~ /FAIL/) {
my $message = "<table><tr><th>Field</th><th>Value</th></tr>\n";
foreach my $key ( keys %{ $params } ) {
$message .= sprintf "<tr><td>%s</td><td>%s</td></tr>\n", $key, $params->{key};
}
$message .= "</table>\n";
return ( 0, $params->{PAYPAL_TX}, $params->{PAYPAL_REQUEST_STATUS}, $message );
}
my $transaction = eval { WebGUI::Shop::Transaction->new($session, $params->{custom}); };
if (my $e = Exception::Class->caught) {
return $self->displayPaymentError();
}
$self->_setPaymentStatus(1, $params->{PAYPAL_TX}, $params->{payment_status}, 'Complete');
$self->processTransaction($transaction);
return $transaction->get('isSuccessful')
return $transaction->isSuccessful
? $transaction->thankYou
: $self->displayPaymentError($transaction);
}

View file

@ -293,10 +293,16 @@ sub _mine_cart {
$self->paymentDriverId($pay->getId);
$self->paymentDriverLabel($pay->get('label'));
##Clear out current transaction items before adding new ones.
foreach my $item (@{$self->getItems}) {
$item->delete;
}
foreach my $item (@{$cart->getItems}) {
$self->addItem({item=>$item});
}
$self->isRecurring( $cart->requiresRecurringPayment );
$self->cashierUserId($cart->getPosUser->userId);
}