Adding Ogone payment plugin

This commit is contained in:
Martin Kamerbeek 2009-05-15 13:29:04 +00:00
parent 1f3b382208
commit 489313a0b9
7 changed files with 1307 additions and 10 deletions

View file

@ -1,5 +1,6 @@
7.7.7
- rfe #10061: Use email as username at registration
- Added Ogone payment plugin ( Martin Kamerbeek / Oqapi )
7.7.6
- Added mobile style template. If enabled in settings, will serve alternate style templates

View file

@ -8,6 +8,10 @@ versions. Be sure to heed the warnings contained herein as they will
save you many hours of grief.
7.7.7
--------------------------------------------------------------------
* WebGUI now requires Digest::SHA.
7.7.6
--------------------------------------------------------------------
* WebGUI now requires Business::Tax::VAT::Validation.

View file

@ -27,23 +27,23 @@ use WebGUI::Asset;
my $toVersion = '7.7.7';
my $quiet; # this line required
my $session = start(); # this line required
# upgrade functions go here
addOgoneToConfig( $session );
addUseEmailAsUsernameToSettings( $session );
finish($session); # this line required
#----------------------------------------------------------------------------
# Describe what our function does
#sub exampleFunction {
# my $session = shift;
# print "\tWe're doing some stuff here that you should know about... " unless $quiet;
# # and here's our code
# print "DONE!\n" unless $quiet;
#}
sub addOgoneToConfig {
my $session = shift;
print "\tAdding Ogone payment plugin..." unless $quiet;
$session->config->addToArray('paymentDrivers', 'WebGUI::Shop::PayDriver::Ogone');
print "Done\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub addUseEmailAsUsernameToSettings {
@ -51,10 +51,10 @@ sub addUseEmailAsUsernameToSettings {
print "\tAdding webguiUseEmailAsUsername to settings \n" unless $quiet;
$session->db->write("insert into settings (name, value) values ('webguiUseEmailAsUsername',0)");
print "Done.\n" unless $quiet;
}
# -------------- DO NOT EDIT BELOW THIS LINE --------------------------------
#----------------------------------------------------------------------------

View file

@ -0,0 +1,565 @@
package WebGUI::Shop::PayDriver::Ogone;
use strict;
use WebGUI::Shop::PayDriver;
use WebGUI::Exception;
use Digest::SHA qw{ sha1_hex };
use WebGUI::International;
use Data::Dumper;
use base qw{ WebGUI::Shop::PayDriver };
#-------------------------------------------------------------------
=head2 canCheckOutCart ( )
Returns whether the cart can be checked out by this plugin.
=cut
sub canCheckoutCart {
my $self = shift;
my $cart = $self->getCart;
return 0 unless $cart->readyForCheckout;
return 0 if $cart->requiresRecurringPayment;
return 1;
}
#-------------------------------------------------------------------
=head2 definition ( session, definition )
See WebGUI::Shop::PayDriver->definition.
=cut
sub definition {
my $class = shift;
my $session = shift;
my $definition = shift;
WebGUI::Error::InvalidParam->throw( error => q{Must provide a session variable} )
unless $session && ref $session eq 'WebGUI::Session';
my $i18n = WebGUI::International->new($session, 'PayDriver_Ogone');
tie my %fields, 'Tie::IxHash';
#TODO: internationilazation
%fields = (
pspid => {
fieldType => 'text',
label => $i18n->get('psp id'),
hoverHelp => $i18n->get('psp id help'),
defaultValue => '',
},
shaSecret => {
fieldType => 'password',
label => $i18n->get('sha secret'),
hoverHelp => $i18n->get('sha secret help'),
},
postbackSecret => {
fieldType => 'password',
label => $i18n->get('postback secret'),
hoverHelp => $i18n->get('postback secret help'),
},
locale => {
fieldType => 'text',
label => $i18n->get('locale'),
hoverHelp => $i18n->get('locale help'),
defaultValue => 'en_US',
maxlength => 5,
size => 5,
},
currency => {
fieldType => 'text',
label => $i18n->get('currency'),
hoverHelp => $i18n->get('currency help'),
defaultValue => 'EUR',
maxlength => 3,
size => 3,
},
useTestMode => {
fieldType => 'yesNo',
label => $i18n->get('use test mode'),
hoverHelp => $i18n->get('use test mode help'),
defaultValue => 1,
},
);
push @{ $definition }, {
name => $i18n->get('Ogone'),
properties => \%fields,
};
return $class->SUPER::definition($session, $definition);
}
#-------------------------------------------------------------------
=head2 getButton ( )
Returns the HTML for a form containing a button that, when clicked, will take the user to the checkout screen of
this plugin.
=cut
sub getButton {
my $self = shift;
my $session = $self->session;
my $i18n = WebGUI::International->new($session, 'PayDriver_Ogone');
my $payForm = WebGUI::Form::formHeader($session)
. $self->getDoFormTags('getCredentials')
. WebGUI::Form::submit($session, {value => $i18n->get('Ogone') })
. WebGUI::Form::formFooter($session);
return $payForm;
}
#-------------------------------------------------------------------
=head2 getCart
Returns the cart for either the current user or the transaction passed back by Ogone.
=cut
sub getCart {
my $self = shift;
my $cart;
if ($self->{_cartId}) {
$cart = WebGUI::Shop::Cart->new( $self->session, $self->{_cartId} );
}
return $cart || $self->SUPER::getCart;
}
#-------------------------------------------------------------------
=head2 processPayment ()
See WebGUI::Shop::PayDriver->processPayment
=cut
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.
my $success = $self->{_transactionSuccessful} || 0;
my $id = $self->{_ogoneId} || undef;
my $status = $self->{_statusCode} || undef;
my $message = $self->{_statusMessage} || 'Waiting for checkout';
return ( $success, $id, $status, $message );
return (0, undef, 1, 'Pending');
}
#-------------------------------------------------------------------
=head2 ogoneCheckoutButton ( transaction, address )
Generates a form with a submit button that, when clicked, posts the payment data for the given transaction to Ogone
and takes the user there.
=head3 transaction
The instanciated transaction that should be paid.
=head3 address
An instanciated WebGUI::Shop::Address object that contains the billing address.
=cut
sub ogoneCheckoutButton {
my $self = shift;
my $transaction = shift;
my $address = shift;
my $session = $self->session;
my $i18n = WebGUI::International->new( $session, 'PayDriver_Ogone' );
$self->{ _ogoneTransaction } = "done" ;
# Ogone needs the transaction amount in cents
my $amount = $transaction->get('amount') * 100;
$amount =~ s/[^\d]//g; # Remove any character from amount except digits.
my $orderId = $transaction->getId;
my $description = "Transaction ID: $orderId";
my $pspId = $self->get('pspid');
my $name = join " ", $address->get( 'firstName' ), $address->get( 'lastName' );
my $email = $address->get('email');
my $currency = $self->get('currency');
# Generate sha signature the payment data
my $passphrase = join '', $orderId, $amount, $currency, $pspId, $self->get('shaSecret');
my $shaSignature = uc sha1_hex( $passphrase );
# Define the data to be sent to ogone
my %parameters = (
PSPID => $pspId,
orderID => $orderId,
amount => $amount,
currency => $currency,
language => $self->get('locale'),
CN => join( " ", $address->get('firstName'), $address->get('lastName') ),
EMAIL => $email,
ownerZIP => $address->get( 'code' ),
owneraddress => join( " ", $address->get('address1'), $address->get('address2'), $address->get('address3') ),
ownercty => $address->get('country'),
ownertown => $address->get('city'),
ownertelno => $address->get('phoneNumber'),
COMPLUS => $self->getCart->getId,
COM => $description,
SHASign => $shaSignature,
accepturl =>
$self->session->url->getSiteURL.'/?shop=pay&method=do&do=acceptTransaction&paymentGatewayId='.$self->getId,
cancelurl =>
$self->session->url->getSiteURL.'/?shop=pay&method=do&do=cancelTransaction&paymentGatewayId='.$self->getId,
declineurl =>
$self->session->url->getSiteURL.'/?shop=pay&method=do&do=declineTransaction&paymentGatewayId='.$self->getId,
exceptionurl =>
$self->session->url->getSiteURL.'/?shop=pay&method=do&do=exceptionTransaction&paymentGatewayId='.$self->getId
);
# Convert payment data to hidden input tags
my $formFields =
join "\n",
map { WebGUI::Form::hidden( $session, { name => $_, value => $parameters{ $_ } } ) }
keys %parameters;
# Construct actual checkout form
my $action = $self->get('useTestMode')
? 'https://secure.ogone.com/ncol/test/orderstandard.asp'
: 'https://secure.ogone.com/ncol/prod/orderstandard.asp'
;
my $form =
WebGUI::Form::formHeader( $session, {
action => $action,
method => 'POST',
enctype => 'application/x-www-form-urlencoded',
} )
. $formFields
. WebGUI::Form::submit( $session, { name => 'submit2', value => $i18n->get('pay') } )
. WebGUI::Form::formFooter( $session );
return $form;
}
#-------------------------------------------------------------------
=head2 www_getCredentials ( [ addressId ] )
Displays the checkout form for this plugin.
=head3 addressId
Optionally supply this variable which will set the payment address to this addressId.
=cut
sub www_getCredentials {
my ($self, $addressId) = @_;
my $session = $self->session;
my $i18n = WebGUI::International->new( $session, 'PayDriver_Ogone' );
# Process address from address book if passed
$addressId = $session->form->process( 'addressId' );
my $address;
if ( $addressId ) {
$address = eval{ $self->getAddress( $addressId ) };
}
else {
$address = $self->getCart->getShippingAddress;
}
my $billingAddressHtml = $address->getHtmlFormatted;
# Fetch transaction
my $transactionId = $session->form->process('transactionId');
my $transaction;
if ($transactionId) {
$transaction = WebGUI::Shop::Transaction->new( $session, $transactionId );
}
# Or generate a new one
unless ($transaction) {
$transaction = $self->processTransaction( $address );
}
# Set the billing address
$transaction->update( {
paymentAddress => $address,
} );
# Generate the json string that defines where the address book posts the selected address
my $callbackParams = {
url => $session->url->page,
params => [
{ name => 'shop', value => 'pay' },
{ name => 'method', value => 'do' },
{ name => 'do', value => 'getCredentials' },
{ name => 'paymentGatewayId', value => $self->getId },
],
};
my $callbackJson = JSON::to_json( $callbackParams );
# Generate 'Choose billing address' button
my $addressButton = WebGUI::Form::formHeader( $session )
. WebGUI::Form::hidden( $session, { name => 'shop', value => 'address' } )
. WebGUI::Form::hidden( $session, { name => 'method', value => 'view' } )
. WebGUI::Form::hidden( $session, { name => 'callback', value => $callbackJson } )
. WebGUI::Form::submit( $session, { value => $i18n->get('choose billing address') } )
. WebGUI::Form::formFooter( $session);
# Generate 'Proceed' button
my $proceedButton = $address
? $self->ogoneCheckoutButton( $transaction, $address )
: $i18n->get('please choose a billing address')
;
return $session->style->userStyle($addressButton.'<br />'.$billingAddressHtml.'<br />'.$proceedButton);
}
#-------------------------------------------------------------------
=head2 checkPostBackSHA ( )
Processes the postback data Ogone sends after a payment/cancelation. Figures out which transaction the data belongs
to and checks whether the data isn't tampered with by comparing SHA hashes.
If everything checks out, returns the instanciated transaction object, otherwise returns undef.
=cut
sub checkPostbackSHA {
my $self = shift;
my $session = $self->session;
my $form = $session->form;
my $url = $session->url;
# Instanciate transaction
my $transactionId = $url->unescape( $form->process( 'orderID' ) );
my $transaction = WebGUI::Shop::Transaction->new( $session, $transactionId );
return undef unless $transaction;
# Fetch and format amount from transaction
my $amount = $transaction->get('amount');
$amount =~ s/\.00$//; # remove trailing .00
my $currency = $self->get('currency');
# Construct the passphrase...
my $passphrase = join '',
$transactionId, $currency, $amount,
map( { $url->unescape( $form->process( $_ ) ) } qw{ PM ACCEPTANCE STATUS CARDNO PAYID NCERROR BRAND } ),
$self->get('postbackSecret');
# and obtain its sha-1 hash in uppercase
my $shaSignature = uc sha1_hex( $passphrase );
# Return the instanciated transaction if the hash is valid, else return undef.
return $transaction if $shaSignature eq $form->process('SHASIGN');
return undef;
}
#-------------------------------------------------------------------
=head2 _setPaymentStatus ( transactionSuccessful, ogoneId, statusCode, statusMessage )
Stores the results of a postback in the object for later use by other methods.
=head3 transactionSuccessful
A boolean indicating whether or not the payment was successful.
=head3 ogoneId
The Ogone issued transaction ID.
=head3 statusCode
The Ogone issued status code.
=head3 statusMessage
The ogone issued status message.
=cut
sub _setPaymentStatus {
my $self = shift;
my ($form, $url) = $self->session->quick( 'form', 'url' );
$self->{_transactionSuccessful} = shift || 0;
$self->{_ogoneId} = shift || undef;
$self->{_statusCode} = shift || undef;
$self->{_statusMessage} = shift || undef;
$self->{_cartId} = $url->unescape( $form->process('COMPLUS') );
}
#-------------------------------------------------------------------
=head2 www_acceptTransaction ( )
The user is redirected to this screen when the payment was successful.
=cut
sub www_acceptTransaction {
my $self = shift;
my $session = $self->session;
my $form = $session->form;
my $transaction = $self->checkPostbackSHA;
return $session->style->userStyle('Invalid postback data.') unless $transaction;
if ( $form->process('NCERROR') == 0 ) {
if ( !$transaction->isSuccessful ) {
$self->_setPaymentStatus( 1, $form->process('PAYID'), $form->process('STATUS'), 'Complete' );
$self->processTransaction( $transaction );
}
return $transaction->thankYou;
}
return $session->style->userStyle( 'An error occurred with your transaction.' );
}
#-------------------------------------------------------------------
=head2 www_cancelTransaction ( )
The user is redirected to this screen when the payment was canceled.
=cut
sub www_cancelTransaction {
my $self = shift;
my $session = $self->session;
my $form = $session->form;
my $transaction = $self->checkPostbackSHA;
return $session->style->userStyle('Invalid postback data.') unless $transaction;
$self->_setPaymentStatus( 0, $form->process('PAYID'), $form->process('STATUS'), 'Cancelled' );
$self->processTransaction( $transaction );
$session->http->setRedirect($self->session->url->getSiteURL.'?shop=cart');
return $session->style->userStyle('Transaction cancelled');
}
#-------------------------------------------------------------------
=head2 www_declineTransaction ( )
The user is redirected to this screen when the payment was declined.
=cut
sub www_declineTransaction {
my $self = shift;
my $session = $self->session;
my $form = $session->form;
my $transaction = $self->checkPostbackSHA;
return $session->style->userStyle('Invalid postback data.') unless $transaction;
$self->_setPaymentStatus( 0, $form->process('PAYID'), $form->process('STATUS'), 'Declined' );
$self->processTransaction( $transaction );
$session->http->setRedirect($self->session->url->getSiteURL.'?shop=cart');
return $session->style->userStyle('Transaction declined');
}
#-------------------------------------------------------------------
=head2 www_exceptionTransaction ( )
The user is redirected to this screen when a payment exception occurred.
=cut
sub www_exceptionTransaction {
my $self = shift;
my $session = $self->session;
my $form = $session->form;
my $transaction = $self->checkPostbackSHA;
return $session->style->userStyle('Invalid postback data.') unless $transaction;
$self->_setPaymentStatus( 0, $form->process('PAYID'), $form->process('STATUS'), 'Transaction exception occurred' );
$self->processTransaction( $transaction );
$session->http->setRedirect($self->session->url->getSiteURL.'?shop=cart');
return $session->style->userStyle('A transaction exception occurred.');
}
#-------------------------------------------------------------------
=head2 www_edit ( )
Displays the properties screen.
=cut
sub www_edit {
my $self = shift;
my $session = $self->session;
my $admin = WebGUI::Shop::Admin->new($session);
my $i18n = WebGUI::International->new($session, 'PayDriver_Ogone');
return $session->privilege->insufficient() unless $admin->canManage;
my $form = $self->getEditForm;
$form->submit;
my $processUrl = $self->session->url->getSiteURL.'/?shop=pay;method=do;do=processTransaction;paymentGatewayId='.$self->getId;
my $output = '<br />';
$output .= sprintf $i18n->get('ogone setup'), $processUrl, $processUrl;
return $admin->getAdminConsole->render($form->print.$output, $i18n->get('payment methods','PayDriver'));
}
#-------------------------------------------------------------------
=head2 www_processTransaction ( )
This method is called by the post sale notfication.
=cut
sub www_processTransaction {
my $self = shift;
my $session = $self->session;
my $form = $session->form;
my $transaction = $self->checkPostbackSHA;
return $session->style->userStyle('Invalid postback data.') unless $transaction;
if ( $form->process('NCERROR') == 0 ) {
if ( !$transaction->isSuccessful ) {
$self->_setPaymentStatus( 1, $form->process('PAYID'), $form->process('STATUS'), 'Complete' );
}
}
else {
$self->_setPaymentStatus( 0, $form->process('PAYID'), $form->process('STATUS'), 'A payment processing error occurred' );
}
$self->processTransaction( $transaction );
return 'ok';
}
1;

View file

@ -0,0 +1,135 @@
package WebGUI::i18n::English::PayDriver_Ogone;
use strict;
our $I18N = {
'Ogone' => {
message => q|Ogone|,
lastUpdated => 0,
context => q|The name of the Ogone plugin|,
},
'psp id' => {
message => q|PSP ID|,
lastUpdated => 0,
context => q|Label of a setting in the ogone config screen.|,
},
'psp id help' => {
message => q|Your ogone username|,
lastUpdated => 0,
context => q|Hover help of a setting in the ogone config screen.|,
},
'sha secret' => {
message => q|Pre payment SHA secret (option 3.2)|,
lastUpdated => 0,
context => q|Label of a setting in the ogone config screen.|,
},
'sha secret help' => {
message => q|The passphrase you set in section 3.2 in the Technical information page of the Ogone interface.|,
lastUpdated => 0,
context => q|Hover help of a setting in the ogone config screen.|,
},
'postback secret' => {
message => q|Post payment SHA secret (option 4.4)|,
lastUpdated => 0,
context => q|Label of a setting in the ogone config screen.|,
},
'postback secret help' => {
message => q|The passphrase you set in section 4.4 in the Technical information page of the Ogone interface.|,
lastUpdated => 0,
context => q|Hover help of a setting in the ogone config screen.|,
},
'locale' => {
message => q|Ogone language|,
lastUpdated => 0,
context => q|Label of a setting in the ogone config screen.|,
},
'locale help' => {
message => q|The locale string for the language the Ogone interface should be displayed in to the user (eg. nl_NL or en_US) |,
lastUpdated => 0,
context => q|Hover help of a setting in the ogone config screen.|,
},
'currency' => {
message => q|Currency (ISO Aplha code)|,
lastUpdated => 0,
context => q|Label of a setting in the ogone config screen.|,
},
'currency help' => {
message => q|The currency in which the payment are to be made. Enter the ISO Alpha code. Commonly used codes are EUR for Euro, USD for US Dollar, CHF for Swiss Franks and GBP for Brittish Pounds. See http://en.wikipedia.org/wiki/ISO_currency_code#Active_codes for a complete list.|,
lastUpdated => 0,
context => q|Hover help of a setting in the ogone config screen.|,
},
'use test mode' => {
message => q|Use in test mode?|,
lastUpdated => 0,
context => q|Label of a setting in the ogone config screen.|,
},
'use test mode help' => {
message => q|Setting this option to yes directs all payment requests to Ogone's test environment. This allows you to check if everything is set up correctlt before going live. No actual payments are being made while test mode is enabled, so don't forget to set this option to 'No' when ready testing.|,
lastUpdated => 0,
context => q|Hover help of a setting in the ogone config screen.|,
},
'pay' => {
message => q|Pay|,
lastUpdated => 0,
context => q|Label of the pay button.|,
},
'choose billing address' => {
message => q|Choose billing address|,
lastUpdated => 0,
context => q|Label of the choose address button.|,
},
'please choose a billing address' => {
message => q|Please choose a billing address.|,
lastUpdated => 0,
context => q|Status message|,
},
'ogone setup' => {
message => q|
<p>In order to use this plugin you need to set up Ogone as well. Please go to the Techincal Information
page in the Ogone admin interface and set the properties listed below. Always start in test mode and
check if everything work alright. When switching to production mode, don't forget to apply the option
below to your production account as well.</p>
<ul>
<li>
<b>4.1 Urls:</b>Set to <i>%s</i>
</li>
<li>
<b>4.2 Request type:</b> Set to 'Make this request just after the payment and let the result
customize the answer seen by customer (HTML code or redirection)'
</li>
<li>
<b>4.4 SHA Signature:</b> Set to the exact sam value as entered above.
</li>
<li>
<b>4.5 Redirection URL's:</b> Make sure the box is checked.
</li>
<li>
<b>7.1 Warn:</b> Set to 'only at the authorisation request of the order'.
</li>
<li>
<b>7.2 How:</b> Select 'Email and http request'. <br /><b>Url for offline httpRequests</b> Set to
<i>%s</i>
</li>
</ul>|,
lastUpdated => 0,
context => q|Text that describes the required Ogone settings.|,
},
};
1;

View file

@ -129,6 +129,7 @@ checkModule('CSS::Packer', '0.2' );
checkModule('Business::Tax::VAT::Validation', '0.20' );
checkModule('Crypt::SSLeay', '0.57' );
checkModule('Scope::Guard', '0.03' );
checkModule('Digest::SHA', '5.47' );
failAndExit("Required modules are missing, running no more checks.") if $missingModule;

591
t/Shop/PayDriver/Ogone.t Normal file
View file

@ -0,0 +1,591 @@
# vim:syntax=perl
#-------------------------------------------------------------------
# WebGUI is Copyright 2001-2008 Plain Black Corporation.
#-------------------------------------------------------------------
# Please read the legal notices (docs/legal.txt) and the license
# (docs/license.txt) that came with this distribution before using
# this software.
#------------------------------------------------------------------
# http://www.plainblack.com info@plainblack.com
#------------------------------------------------------------------
# Write a little about what this script tests.
#
#
use FindBin;
use strict;
use lib "$FindBin::Bin/../../lib";
use Test::More;
use Test::Deep;
use WebGUI::Test; # Must use this before any other WebGUI modules
use WebGUI::Session;
use JSON;
use HTML::Form;
#----------------------------------------------------------------------------
# Init
my $session = WebGUI::Test->session;
#----------------------------------------------------------------------------
# Tests
my $tests = 45;
plan tests => 1 + $tests;
#----------------------------------------------------------------------------
# figure out if the test can actually run
my $e;
diag('Testing existence');
my $loaded = use_ok('WebGUI::Shop::PayDriver::Ogone');
SKIP: {
skip 'Unable to load module WebGUI::Shop::PayDriver::Ogone', $tests unless $loaded;
#######################################################################
#
# definition
#
#######################################################################
diag('Testing definition');
my $definition;
eval { $definition = WebGUI::Shop::PayDriver::Ogone->definition(); };
$e = Exception::Class->caught();
isa_ok ($e, 'WebGUI::Error::InvalidParam', 'definition takes an exception to not giving it a session variable');
cmp_deeply (
$e,
methods(
error => 'Must provide a session variable',
),
'definition: requires a session variable',
);
$definition = WebGUI::Shop::PayDriver::Ogone->definition($session);
use Data::Dumper;
my $expectDefinition = {
name => 'Ogone',
properties => {
pspid => {
fieldType => 'text',
label => ignore(),
hoverHelp => ignore(),
defaultValue => q{}
},
shaSecret => {
fieldType => 'password',
label => ignore(),
hoverHelp => ignore(),
},
postbackSecret => {
fieldType => 'password',
label => ignore(),
hoverHelp => ignore(),
},
locale => {
fieldType => 'text',
label => ignore(),
hoverHelp => ignore(),
defaultValue => 'en_US',
maxlength => 5,
size => 5,
},
currency => {
fieldType => 'text',
label => ignore(),
hoverHelp => ignore(),
defaultValue => 'EUR',
maxlength => 3,
size => 3,
},
useTestMode => {
fieldType => 'yesNo',
label => ignore(),
hoverHelp => ignore(),
defaultValue => 1,
},
},
};
cmp_deeply ( $definition->[0], $expectDefinition, 'Definition returns an array of hashrefs' );
$definition = WebGUI::Shop::PayDriver::Ogone->definition($session, [ { name => 'Ogone First' }]);
cmp_deeply (
$definition,
[
{
name => 'Ogone First',
},
{
name => 'Ogone',
properties => ignore(),
},
{
name => 'Payment Driver',
properties => ignore(),
}
],
,
'New data is appended correctly',
);
#######################################################################
#
# create
#
#######################################################################
my $driver;
# Test incorrect for parameters
eval { $driver = WebGUI::Shop::PayDriver::Ogone->create(); };
$e = Exception::Class->caught();
isa_ok ($e, 'WebGUI::Error::InvalidParam', 'create takes exception to not giving it a session object');
cmp_deeply (
$e,
methods(
error => 'Must provide a session variable',
),
'create takes exception to not giving it a session object',
);
eval { $driver = WebGUI::Shop::PayDriver::Ogone->create($session, {}); };
$e = Exception::Class->caught();
isa_ok ($e, 'WebGUI::Error::InvalidParam', 'create takes exception to giving it an empty hashref of options');
cmp_deeply (
$e,
methods(
error => 'Must provide a hashref of options',
),
'create takes exception to not giving it an empty hashref of options',
);
# Test functionality
my $signature = '-----BEGIN PKCS7-----
MIIHPwYJKoZIhvcNAQcEoIIHMDCCBywCAQExggE0MIIB
MAIBADCBmDCBkjELMAkGA1UEBhMCVVMxCzAJBgNVBAgT
AkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYD
VQQKEwtQYXlQYWwgSW5jLjEVMBMGA1UECxQMc3RhZ2Ux
X2NlcnRzMRMwEQYDVQQDFApzdGFnZTFfYXBpMRwwGgYJ
KoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tAgEAMA0GCSqG
SIb3DQEBAQUABIGAiJLqJ8905lNbvKoa715KsOJtSOGy
4d6fEKV7+S8KU8E/RK0SFmMgGPRpmXdzx9MXCU43/tXj
lyuyOeZQUBaAIaWoNpfZmBUYIvJVh4W+bDH6JUkugelp
CaTjxXOx/F1qj79D9z06AK+N3yW1fM41fM7X9Q1Bc12g
THjJUKXcIIcxCzAJBgUrDgMCGgUAMIGkBgkqhkiG9w0B
BwEwFAYIKoZIhvcNAwcECOsHG9QOvcJFgIGAwmbN5Acd
cnCH0ZTnsSOq5GtXeQf0j2jCBCg6y7b4ZXQwgdqUC/7x
eb0yicuiRVuRB9WLr/0rGFuSYENpKVUqWYjnlg3TsxLP
IxDCp6lfFqsrclppyZ9CP+xim7y0qKqZZufJG8HgCHxk
3BPD6LqByjQjDVpqKKmCNJ1HlwXGN+SgggOWMIIDkjCC
AvugAwIBAgIBADANBgkqhkiG9w0BAQQFADCBkzELMAkG
A1UEBhMCVVMxCzAJBgNVBAgTAkNBMREwDwYDVQQHEwhT
YW4gSm9zZTEPMA0GA1UEChMGUGF5UGFsMRwwGgYDVQQL
ExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRMwEQYDVQQDEwpT
b3V2aWsgRGFzMSAwHgYJKoZIhvcNAQkBFhFzb3VkYXNA
cGF5cGFsLmNvbTAeFw0wNDA1MjExODE4NTBaFw0wNDA2
MjAxODE4NTBaMIGTMQswCQYDVQQGEwJVUzELMAkGA1UE
CBMCQ0ExETAPBgNVBAcTCFNhbiBKb3NlMQ8wDQYDVQQK
EwZQYXlQYWwxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5l
ZXJpbmcxEzARBgNVBAMTClNvdXZpayBEYXMxIDAeBgkq
hkiG9w0BCQEWEXNvdWRhc0BwYXlwYWwuY29tMIGfMA0G
CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDatyhVzmVe+kCN
tOSNS+c7p9pNHlFGbGtIWgIAKSOVlaTk4JD/UAvQzYnn
eWPUk+Xb5ShTx8YRDEtRtecy/PwSIIrtS2sC8RrmjZxU
uNRqPB6y1ahGwGcNd/wOIy3FekGE/ctX7oG6/Voz/E2Z
EyJaPm7KwYiDQYz7kWJ6eB+kDwIDAQABo4HzMIHwMB0G
A1UdDgQWBBQx23WZRMmnADSXDr+P7uxORBdDuzCBwAYD
VR0jBIG4MIG1gBQx23WZRMmnADSXDr+P7uxORBdDu6GB
maSBljCBkzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNB
MREwDwYDVQQHEwhTYW4gSm9zZTEPMA0GA1UEChMGUGF5
UGFsMRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5n
MRMwEQYDVQQDEwpTb3V2aWsgRGFzMSAwHgYJKoZIhvcN
AQkBFhFzb3VkYXNAcGF5cGFsLmNvbYIBADAMBgNVHRME
BTADAQH/MA0GCSqGSIb3DQEBBAUAA4GBAIBlMsXVnxYe
ZtVTG3rsVYePdkMs+0WdRd+prTK4ZBcAkCyNk9jCq5dy
VziCi4ZCleMqR5Y0NH1+BQAf8vxxcb4Z7p0rryXGb96f
ZfkSYd99a4qGKW3aSIsc2kpaC/ezQg8vuD6JSo6VhJIb
Zn0oWajvkHNMENOwN/Ym5stvAxtnMYIBnzCCAZsCAQEw
gZkwgZMxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTER
MA8GA1UEBxMIU2FuIEpvc2UxDzANBgNVBAoTBlBheVBh
bDEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmluZzET
MBEGA1UEAxMKU291dmlrIERhczEgMB4GCSqGSIb3DQEJ
ARYRc291ZGFzQHBheXBhbC5jb20CAQAwCQYFKw4DAhoF
AKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJ
KoZIhvcNAQkFMQ8XDTA0MDUyNjE5MTgxNFowIwYJKoZI
hvcNAQkEMRYEFI2w1oe5qvHYB0w9Z/ntkRcDqLlhMA0G
CSqGSIb3DQEBAQUABIGAimA3r6ZXmyynFGF5cOj6E1Hq
Ebtelq2tg4HroAHZLWoQ3kc/7IM0LCuWZmgtD5739NSS
0+tOFSdH68sxKsdooR3MFTbdzWhtej5fPKRa6BfHGPjI
9R9NoAQBmaeUuOiPSeVTzXDOKDbZB0sJtmWNeueTD9D0
BOu+vkC1g+HRToc=
-----END PKCS7-----';
my $options = {
label => 'Fast and harmless',
enabled => 1,
group => 3,
receiptMessage => 'Pannenkoeken zijn nog lekkerder met kaas',
vendorId => 'oqapi',
signature => $signature,
currency => 'EUR',
useSandbox => '0',
emailMessage => 'Thank you very very much'
};
$driver = WebGUI::Shop::PayDriver::Ogone->create( $session, $options );
isa_ok ($driver, 'WebGUI::Shop::PayDriver::Ogone', 'create creates WebGUI::Shop::PayDriver object');
like($driver->getId, $session->id->getValidator, 'driver id is a valid GUID');
my $dbData = $session->db->quickHashRef('select * from paymentGateway where paymentGatewayId=?', [ $driver->getId ]);
cmp_deeply (
$dbData,
{
paymentGatewayId => $driver->getId,
className => ref $driver,
options => ignore()
},
'Correct data written to the db',
);
my $paymentGatewayOptions = from_json($dbData->{'options'});
cmp_deeply (
$paymentGatewayOptions,
{
"group" => 3,
"receiptMessage" => 'Pannenkoeken zijn nog lekkerder met kaas',
"label" => 'Fast and harmless',
"enabled" => 1,
"vendorId" => 'oqapi',
"signature" => $signature,
"currency" => 'EUR',
"useSandbox" => '0',
"emailMessage" => 'Thank you very very much'
},
'Correct options are written to the db'
);
#######################################################################
#
# session
#
#######################################################################
isa_ok ($driver->session, 'WebGUI::Session', 'session method returns a session object');
is ($session->getId, $driver->session->getId, 'session method returns OUR session object');
#######################################################################
#
# paymentGatewayId, getId
#
#######################################################################
like ($driver->paymentGatewayId, $session->id->getValidator, 'got a valid GUID for paymentGatewayId');
is ($driver->getId, $driver->paymentGatewayId, 'getId returns the same thing as paymentGatewayId');
#######################################################################
#
# className
#
#######################################################################
is ($driver->className, ref $driver, 'className property set correctly');
#######################################################################
#
# options
#
#######################################################################
cmp_deeply ($driver->options, $options, 'options accessor works');
#######################################################################
#
# getName
#
#######################################################################
eval { WebGUI::Shop::PayDriver->getName(); };
$e = Exception::Class->caught();
isa_ok ($e, 'WebGUI::Error::InvalidParam', 'getName requires a session object passed to it');
cmp_deeply (
$e,
methods(
error => 'Must provide a session variable',
),
'getName requires a session object passed to it',
);
is (WebGUI::Shop::PayDriver->getName($session), 'Payment Driver', 'getName returns the human readable name of this driver');
#######################################################################
#
# get
#
#######################################################################
cmp_deeply ($driver->get, $driver->options, 'get works like the options method with no param passed');
is ($driver->get('enabled'), 1, 'get the enabled entry from the options');
is ($driver->get('label'), 'Fast and harmless', 'get the label entry from the options');
my $optionsCopy = $driver->get;
$optionsCopy->{label} = 'And now for something completely different';
isnt(
$driver->get('label'),
'And now for something completely different',
'hashref returned by get() is a copy of the internal hashref'
);
#######################################################################
#
# getCart
#
#######################################################################
my $cart = $driver->getCart;
isa_ok ($cart, 'WebGUI::Shop::Cart', 'getCart returns an instantiated WebGUI::Shop::Cart object');
#######################################################################
#
# getEditForm
#
#######################################################################
my $form = $driver->getEditForm;
isa_ok ($form, 'WebGUI::HTMLForm', 'getEditForm returns an HTMLForm object');
my $html = $form->print;
##Any URL is fine, really
my @forms = HTML::Form->parse($html, 'http://www.webgui.org');
is (scalar @forms, 1, 'getEditForm generates just 1 form');
my @inputs = $forms[0]->inputs;
is (scalar @inputs, 19, 'getEditForm: the form has 19 controls');
my @interestingFeatures;
foreach my $input (@inputs) {
my $name = $input->name;
my $type = $input->type;
push @interestingFeatures, { name => $name, type => $type };
}
cmp_deeply(
\@interestingFeatures,
[
{
name => undef,
type => 'submit',
},
{
name => 'shop',
type => 'hidden',
},
{
name => 'method',
type => 'hidden',
},
{
name => 'do',
type => 'hidden',
},
{
name => 'paymentGatewayId',
type => 'hidden',
},
{
name => 'className',
type => 'hidden',
},
{
name => 'label',
type => 'text',
},
{
name => 'enabled',
type => 'radio',
},
{
name => 'groupToUse',
type => 'option',
},
{
name => '__groupToUse_isIn',
type => 'hidden',
},
{
name => 'receiptEmailTemplateId',
type => 'option',
},
{
name => 'saleNotificationGroupId',
type => 'option',
},
{
name => '__saleNotificationGroupId_isIn',
type => 'hidden',
},
{
name => 'pspid',
type => 'text',
},
{
name => 'shaSecret',
type => 'password',
},
{
name => 'postbackSecret',
type => 'password',
},
{
name => 'locale',
type => 'text',
},
{
name => 'currency',
type => 'text',
},
{
name => 'useTestMode',
type => 'radio',
},
],
'getEditForm made the correct form with all the elements'
);
#######################################################################
#
# new
#
#######################################################################
my $oldDriver;
eval { $oldDriver = WebGUI::Shop::PayDriver::Ogone->new(); };
$e = Exception::Class->caught();
isa_ok ($e, 'WebGUI::Error::InvalidParam', 'new takes exception to not giving it a session object');
cmp_deeply (
$e,
methods(
error => 'Must provide a session variable',
),
'new takes exception to not giving it a session object',
);
eval { $oldDriver = WebGUI::Shop::PayDriver::Ogone->new($session); };
$e = Exception::Class->caught();
isa_ok ($e, 'WebGUI::Error::InvalidParam', 'new takes exception to not giving it a paymentGatewayId');
cmp_deeply (
$e,
methods(
error => 'Must provide a paymentGatewayId',
),
'new takes exception to not giving it a paymentGatewayId',
);
eval { $oldDriver = WebGUI::Shop::PayDriver::Ogone->new($session, 'notEverAnId'); };
$e = Exception::Class->caught();
isa_ok ($e, 'WebGUI::Error::ObjectNotFound', 'new croaks unless the requested paymentGatewayId object exists in the db');
cmp_deeply (
$e,
methods(
error => 'paymentGatewayId not found in db',
id => 'notEverAnId',
),
'new croaks unless the requested paymentGatewayId object exists in the db',
);
my $driverCopy = WebGUI::Shop::PayDriver::Ogone->new($session, $driver->getId);
is ($driver->getId, $driverCopy->getId, 'same id');
is ($driver->className, $driverCopy->className, 'same className');
cmp_deeply ($driver->options, $driverCopy->options, 'same options');
#######################################################################
#
# update
#
#######################################################################
eval { $driver->update(); };
$e = Exception::Class->caught();
isa_ok ($e, 'WebGUI::Error::InvalidParam', 'update takes exception to not giving it a hashref of options');
cmp_deeply (
$e,
methods(
error => 'update was not sent a hashref of options to store in the database',
),
'update takes exception to not giving it a hashref of options',
);
my $newOptions = {
label => 'Yet another label',
enabled => 0,
group => 4,
receiptMessage => 'Dropjes!',
};
$driver->update($newOptions);
my $storedOptions = $session->db->quickScalar('select options from paymentGateway where paymentGatewayId=?', [
$driver->getId,
]);
cmp_deeply(
$newOptions,
from_json($storedOptions),
,
'update() actually stores data',
);
#######################################################################
#
# canUse
#
#######################################################################
$session->user({userId => 3});
ok($driver->canUse, 'canUse: session->user is used if no argument is passed');
ok(!$driver->canUse({userId => 1}), 'canUse: userId explicit works, visitor cannot use this driver');
#######################################################################
#
# delete
#
#######################################################################
$driver->delete;
my $count = $session->db->quickScalar('select count(*) from paymentGateway where paymentGatewayId=?', [
$driver->paymentGatewayId
]);
is ($count, 0, 'delete deleted the object');
undef $driver;
#----------------------------------------------------------------------------
# Cleanup
}
END {
}
#vim:ft=perl