diff --git a/docs/upgrades/upgrade_7.5.2-7.5.3.pl b/docs/upgrades/upgrade_7.5.2-7.5.3.pl index d6ebecafb..a674c0827 100644 --- a/docs/upgrades/upgrade_7.5.2-7.5.3.pl +++ b/docs/upgrades/upgrade_7.5.2-7.5.3.pl @@ -33,6 +33,7 @@ createDonationAsset($session); addShippingDrivers($session); addShoppingHandler($session); addAddressBook($session); +insertCommercePayDriverTable($session); addPaymentDrivers($session); finish($session); # this line required @@ -215,6 +216,20 @@ sub addShippingDrivers { $session->config->addToArray('shippingDrivers', 'WebGUI::Shop::ShipDriver::FlatRate'); } +#------------------------------------------------- +sub insertCommercePayDriverTable { + my $session = shift; + print "\tInstall the Commerce PayDriver Table.\n" unless ($quiet); + # and here's our code + $session->db->write(<new($session); + +=head1 METHODS + +These subroutines are available from this package: + +=cut + +readonly session => my %session; +readonly className => my %className; +readonly paymentGatewayId => my %paymentGatewayId; +readonly options => my %options; +readonly label => my %label; + +#------------------------------------------------------------------- + +=head2 _buildObj ( ) + +Private method used to build objects, shared by new and create. + +=cut + +sub _buildObj { + my ($class, $session, $requestedClass, $paymentGatewayId, $label, $options) = @_; + my $self = {}; + bless $self, $requestedClass; + register $self; + + my $id = id $self; + + $session{ $id } = $session; + $paymentGatewayId{ $id } = $paymentGatewayId; + $label{ $id } = $label; + $options{ $id } = $options; + $className{ $id } = $requestedClass; + + return $self; +} + + +#------------------------------------------------------------------- + +=head2 className ( ) + +Accessor for the className of the object. This is the name of the driver that is used +to do calculations. + +=cut + +#------------------------------------------------------------------- + +=head2 create ( $session, $label, $options ) + +Constructor for new WebGUI::Shop::PayDriver objects. Returns a WebGUI::Shop::PayDriver object. +To access driver objects that have already been configured, use C. + +=head3 $session + +A WebGUI::Session object. + +=head4 $label + +A human readable label for this payment. + +=head4 $options + +A list of properties to assign to this PayDriver. See C for details. + +=cut + +sub create { + my $class = shift; + my $session = shift; + WebGUI::Error::InvalidParam->throw(error => q{Must provide a session variable}) + unless ref $session eq 'WebGUI::Session'; + my $label = shift; + WebGUI::Error::InvalidParam->throw(error => q{Must provide a human readable label in the hashref of options}) + unless $label; + my $options = shift; + WebGUI::Error::InvalidParam->throw(error => q{Must provide a hashref of options}) + unless ref $options eq 'HASH' and scalar keys %{ $options }; + + # Generate a unique id for this payment + my $paymentGatewayId = $session->id->generate; + + # Build object + my $self = WebGUI::Shop::PayDriver->_buildObj($session, $class, $paymentGatewayId, $label, $options); + + # and persist this instance in the db + $session->db->write('insert into payment_Gateway (paymentGatewayId, label, className) VALUES (?,?,?)', [ + $paymentGatewayId, + $label, + $class, + ]); + + # Set the options via the set method because set() will automatically serialize the options hash + $self->set($options); + + return $self; +} + +#------------------------------------------------------------------- + +=head2 definition ( $session ) + +This subroutine returns an arrayref of hashrefs, used to validate data put into +the object by the user, and to automatically generate the edit form to show +the user. + +=cut + +sub definition { + my $class = shift; + my $session = shift; + WebGUI::Error::InvalidParam->throw(error => q{Must provide a session variable}) + unless ref $session eq 'WebGUI::Session'; + my $definition = shift || []; + + my $i18n = WebGUI::International->new($session, 'PayDriver'); + + tie my %fields, 'Tie::IxHash'; + %fields = ( + label => { + fieldType => 'text', + label => $i18n->echo('label'), + hoverHelp => $i18n->echo('label help'), + defaultValue => "Credit Card", + }, + enabled => { + fieldType => 'yesNo', + label => $i18n->echo('enabled'), + hoverHelp => $i18n->echo('enabled help'), + defaultValue => 1, + }, + groupToUse => { + fieldType => 'group', + label => $i18n->echo('who can use'), + hoverHelp => $i18n->echo('who can use help'), + defaultValue => 1, + }, + receiptMessage => { + fieldType => 'text', + label => $i18n->echo('receipt message'), + hoverHelp => $i18n->echo('receipt message help'), + defaultValue => undef, + }, + ); + + my %properties = ( + name => 'Payment Driver', + fields => \%fields, + ); + push @{ $definition }, \%properties; + + return $definition; +} + +#------------------------------------------------------------------- + +=head2 delete ( ) + +Removes this PayDriver object from the db. + +=cut + +sub delete { + my $self = shift; + + $self->session->db->write('delete from payment_Gateway where paymentGatewayId=?', [ + $self->getId, + ]); + + return; +} + +#------------------------------------------------------------------- + +=head2 get ( [ $param ] ) + +This is an enhanced accessor for the options property. By default, +it returns all the options as a hashref. If the name of a key +in the hash is passed, it will only return that value from the +options hash. + +=head3 $param + +An optional parameter. If it matches the key of a hash, it will +return the value from the options hash. + +=cut + +sub get { + my $self = shift; + my $param = shift; + my $options = $self->options; + if (defined $param) { + return $options->{ $param }; + } + else { + return { %$options }; + } +} + +#------------------------------------------------------------------- + +=head2 getButton ( ) + +Returns the form that will take the user to check out. + +=cut + +sub getButton { + my $self = shift; +} + +#------------------------------------------------------------------- + +=head2 getEditForm ( ) + +Returns the configuration form for the options of this plugin. + +=cut + +sub getEditForm { + my $self = shift; + + my $definition = $self->definition($self->session); + my $form = WebGUI::HTMLForm->new($self->session); + $form->submit; + $form->hidden( + name => 'paymentGatewayId', + value => $self->getId, + ); + $form->hidden( + name => 'className', + value => $self->className, + ); + $form->dynamicForm($definition, 'fields', $self); + + return $form; +} + +#------------------------------------------------------------------- + +=head2 getId ( ) + +Returns the paymentGatewayId. + +=cut + +sub getId { + my $self = shift; + + return $self->paymentGatewayId; +} + +#------------------------------------------------------------------- + +=head2 getName ( ) + +Return a human readable name for this driver. Never overridden in the +subclass, instead specified in definition with the name "name". + +=cut + +sub getName { + my $self = shift; + my $definition = $self->definition($self->session); + return $definition->[0]->{name}; +} + +#------------------------------------------------------------------- + +=head2 new ( $session, $paymentGatewayId ) + +Looks up an existing PayDriver in the db by paymentGatewayId and returns +that object. + +=cut + +sub new { + my $class = shift; + my $session = shift; + WebGUI::Error::InvalidParam->throw(error => q{Must provide a session variable}) + unless ref $session eq 'WebGUI::Session'; + my $paymentGatewayId = shift; + WebGUI::Error::InvalidParam->throw(error => q{Must provide a paymentGatewayId}) + unless defined $paymentGatewayId; + + # Fetch the instance data from the db + my $properties = $session->db->quickHashRef('select * from payment_Gateway where paymentGatewayId=?', [ + $paymentGatewayId, + ]); + WebGUI::Error::ObjectNotFound->throw(error => q{paymentGatewayId not found in db}, id => $paymentGatewayId) + unless scalar keys %{ $properties }; + + croak "Somehow, the options property of this object, $paymentGatewayId, got broken in the db" + unless exists $properties->{options} and $properties->{options}; + + #### TODO: Fix deprecated json sub + my $options = from_json($properties->{options}); + + my $self = WebGUI::Shop::PayDriver->_buildObj($session, $class, $paymentGatewayId, $properties->{ label }, $options); + + return $self; +} + +#------------------------------------------------------------------- + +=head2 options ( ) + +Accessor for the driver properties. This returns a hashref +any driver specific properties. To set the properties, use +the C method. + +=cut + +#------------------------------------------------------------------- + +=head2 session ( ) + +Accessor for the session object. Returns the session object. + +=cut + +#------------------------------------------------------------------- + +=head2 set ( $options ) + +Setter for user configurable options in the payment objects. + +=head4 $options + +A list of properties to assign to this PayDriver. See C for details. The options are +flattened into JSON and stored in the database as text. There is no content checking performed. + +=cut + +#### TODO: decide on what set() sets. Ie. does it only set options, or also label? +sub set { + my $self = shift; + my $properties = shift; + WebGUI::Error::InvalidParam->throw(error => 'set was not sent a hashref of options to store in the database') + unless ref $properties eq 'HASH' and scalar keys %{ $properties }; + + my $jsonOptions = to_json($properties); + $self->session->db->write('update payment_Gateway set options=? where paymentGatewayId=?', [ + $jsonOptions, + $self->paymentGatewayId + ]); + + return; +} + +#------------------------------------------------------------------- + +=head2 paymentGatewayId ( ) + +Accessor for the unique identifier for this PayDriver. The paymentGatewayId is +a GUID. + +=cut + +1; diff --git a/t/Shop/PayDriver.t b/t/Shop/PayDriver.t new file mode 100644 index 000000000..ff5f200e2 --- /dev/null +++ b/t/Shop/PayDriver.t @@ -0,0 +1,440 @@ +# 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 JSON; +use HTML::Form; + +use WebGUI::Test; # Must use this before any other WebGUI modules +use WebGUI::Session; + +#---------------------------------------------------------------------------- +# Init +my $session = WebGUI::Test->session; + +#---------------------------------------------------------------------------- +# Tests + +my $tests = 43; +plan tests => 1 + $tests; + +#---------------------------------------------------------------------------- +# figure out if the test can actually run + +my $e; + +my $loaded = use_ok('WebGUI::Shop::PayDriver'); + +my $storage; + +SKIP: { + +skip 'Unable to load module WebGUI::Shop::PayDriver', $tests unless $loaded; + +####################################################################### +# +# definition +# +####################################################################### + +my $definition; + +eval { $definition = WebGUI::Shop::PayDriver->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->definition($session); + +cmp_deeply ( + $definition, + [ { + name => 'Payment Driver', + fields => { + label => { + fieldType => 'text', + label => ignore(), + hoverHelp => ignore(), + defaultValue => "Credit Card", + }, + enabled => { + fieldType => 'yesNo', + label => ignore(), + hoverHelp => ignore(), + defaultValue => 1, + }, + groupToUse => { + fieldType => 'group', + label => ignore(), + hoverHelp => ignore(), + defaultValue => 1, + }, + receiptMessage => { + fieldType => 'text', + label => ignore(), + hoverHelp => ignore(), + defaultValue => undef, + }, + } + } ], + , + 'Definition returns an array of hashrefs', +); + +$definition = WebGUI::Shop::PayDriver->definition($session, [ { name => 'Red' }]); + +cmp_deeply ( + $definition, + [ + { + name => 'Red', + }, + { + name => 'Payment Driver', + fields => ignore(), + } + ], + , + 'New data is appended correctly', +); + +####################################################################### +# +# create +# +####################################################################### + +my $driver; + +# Test incorrect for parameters + +eval { $driver = WebGUI::Shop::PayDriver->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->create($session); }; +$e = Exception::Class->caught(); +isa_ok ($e, 'WebGUI::Error::InvalidParam', 'create takes exception to not giving it a label'); +cmp_deeply ( + $e, + methods( + error => 'Must provide a human readable label in the hashref of options', + ), + 'create takes exception to not giving it a hashref of options', +); + +eval { $driver = WebGUI::Shop::PayDriver->create($session, 'Very human readable label'); }; +$e = Exception::Class->caught(); +isa_ok ($e, 'WebGUI::Error::InvalidParam', 'create takes exception to not giving it a hashref of options'); +cmp_deeply ( + $e, + methods( + error => 'Must provide a hashref of options', + ), + 'create takes exception to not giving it a hashref of options', +); + +eval { $driver = WebGUI::Shop::PayDriver->create($session, 'Very human readable label', {}); }; +$e = Exception::Class->caught(); +isa_ok ($e, 'WebGUI::Error::InvalidParam', 'create takes exception to not 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 $label = 'Human Readable Label'; +my $options = { + label => 'Fast and harmless', + enabled => 1, + group => 3, + receiptMessage => 'Pannenkoeken zijn nog lekkerder met spek', +}; + +$driver = WebGUI::Shop::PayDriver->create( $session, $label, $options ); + +isa_ok ($driver, 'WebGUI::Shop::PayDriver', 'create creates WebGUI::Shop::PayDriver object'); + +my $dbData = $session->db->quickHashRef('select * from payment_Gateway where paymentGatewayId=?', [ $driver->getId ]); + +#diag ($driver->getId); +cmp_deeply ( + $dbData, + { + paymentGatewayId => $driver->getId, + className => ref $driver, + label => $driver->label, + options => q|{"group":3,"receiptMessage":"Pannenkoeken zijn nog lekkerder met spek","label":"Fast and harmless","enabled":1}|, + }, + 'Correct data 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 +# +####################################################################### + +is ($driver->getName, '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'); + +####################################################################### +# +# 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, 7, 'getEditForm: the form has 7 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 => 'paymentGatewayId', + type => 'hidden', + }, + { + name => 'className', + type => 'hidden', + }, + { + name => 'label', + type => 'text', + }, + { + name => 'enabled', + type => 'radio', + }, + { + name => 'groupToUse', + type => 'option', + }, + { + name => 'receiptMessage', + type => 'text', + }, + ], + 'getEditForm made the correct form with all the elements' + +); + + +####################################################################### +# +# new +# +####################################################################### + +my $oldDriver; + +eval { $oldDriver = WebGUI::Shop::PayDriver->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->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->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->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'); + +TODO: { + local $TODO = 'tests for new'; + ok(0, 'Test broken options in the db'); +} + +####################################################################### +# +# set +# +####################################################################### + +eval { $driver->set(); }; +$e = Exception::Class->caught(); +isa_ok ($e, 'WebGUI::Error::InvalidParam', 'set takes exception to not giving it a hashref of options'); +cmp_deeply ( + $e, + methods( + error => 'set was not sent a hashref of options to store in the database', + ), + 'set takes exception to not giving it a hashref of options', +); + +my $newOptions = { + label => 'Yet another label', + enabled => 0, + group => 4, + receiptMessage => 'Dropjes!', +}; + +$driver->set($newOptions); +my $storedOptions = $session->db->quickScalar('select options from payment_Gateway where paymentGatewayId=?', [ + $driver->getId, +]); +cmp_deeply( + $newOptions, + from_json($storedOptions), + , + 'set() actually stores data', +); + + +####################################################################### +# +# delete +# +####################################################################### + +$driver->delete; + +my $count = $session->db->quickScalar('select count(*) from payment_Gateway where paymentGatewayId=?', [ + $driver->paymentGatewayId +]); + +is ($count, 0, 'delete deleted the object'); + +undef $driver; + + +} + +#---------------------------------------------------------------------------- +# Cleanup +END { + #$session->db->write('delete from payment_Gateway'); +}