diff --git a/docs/upgrades/upgrade_7.5.10-7.5.11.pl b/docs/upgrades/upgrade_7.5.10-7.5.11.pl
index 2e4c8f6a3..f3cbba9cc 100644
--- a/docs/upgrades/upgrade_7.5.10-7.5.11.pl
+++ b/docs/upgrades/upgrade_7.5.10-7.5.11.pl
@@ -64,6 +64,7 @@ migrateSubscriptions( $session );
updateUsersOfCommerceMacros($session);
addDBLinkAccessToSQLMacro($session);
addAssetManager( $session );
+migratePaymentPlugins( $session );
finish($session); # this line required
@@ -1386,6 +1387,33 @@ sub addDBLinkAccessToSQLMacro {
print "Done.\n" unless $quiet;
}
+#----------------------------------------------------------------------------
+sub migratePaymentPlugins {
+ my $session = shift;
+ print "\tMigrating WebGUI default commerce plugins..." unless $quiet;
+
+ foreach my $namespace (qw{ Cash ITransact }) {
+ my $properties = $session->db->buildHashRef(
+ 'select fieldName, fieldValue from commerceSettings where type=\'Payment\' and namespace=?',
+ [
+ $namespace,
+ ]
+ );
+
+ $properties->{ groupToUse } = $properties->{ whoCanUse };
+
+ my $plugin = eval {
+ WebGUI::Pluggable::instanciate("WebGUI::Shop::PayDriver::$namespace", 'create', [
+ $session,
+ $properties->{ label },
+ $properties
+ ])
+ };
+ }
+
+ print "Done\n" unless $quiet;
+}
+
# -------------- DO NOT EDIT BELOW THIS LINE --------------------------------
#----------------------------------------------------------------------------
diff --git a/lib/WebGUI/Shop/Pay.pm b/lib/WebGUI/Shop/Pay.pm
index 748608e42..d91cab049 100644
--- a/lib/WebGUI/Shop/Pay.pm
+++ b/lib/WebGUI/Shop/Pay.pm
@@ -182,7 +182,7 @@ sub getRecurringPeriodValues {
my $self = shift;
my $session = $self->session;
- my $i18n = WebGUI::International->new($session, 'Commerce');
+ my $i18n = WebGUI::International->new($session, 'Shop');
tie my %periods, "Tie::IxHash";
%periods = (
Weekly => $i18n->get('weekly'),
diff --git a/lib/WebGUI/Shop/PayDriver.pm b/lib/WebGUI/Shop/PayDriver.pm
index 47018a5fd..d10afee3d 100644
--- a/lib/WebGUI/Shop/PayDriver.pm
+++ b/lib/WebGUI/Shop/PayDriver.pm
@@ -183,10 +183,10 @@ sub definition {
},
receiptEmailTemplateId => {
fieldType => 'template',
- namespace => "Shop/EmailReceipt",
+ namespace => "Shop/ReceiptEmail",
label => $i18n->get("receipt email template"),
hoverHelp => $i18n->get("receipt email template help"),
- defaultValue => '',
+ defaultValue => 'BMzuE91-XB8E-XGll1zpvA',
},
saleNotificationGroupId => {
fieldType => 'group',
@@ -410,6 +410,51 @@ sub getName {
#-------------------------------------------------------------------
+=head2 getSelectAddressButton ( returnMethod, [ buttonLabel ] )
+
+Generates a button for selecting an address.
+
+=head3 returnMethod
+
+The name of the www_ method the selected addressId should be returned to. Without the 'www_' part.
+
+=head3 buttonLabel
+
+The label for the button, defaults to the internationalized version of 'Choose billing address'.
+
+=cut
+
+sub getSelectAddressButton {
+ my $self = shift;
+ my $returnMethod = shift;
+ my $buttonLabel = shift || 'Choose billing address';
+ my $session = $self->session;
+
+ # 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 => $returnMethod },
+ { 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 => $buttonLabel } )
+ . WebGUI::Form::formFooter( $session );
+
+ return $addressButton;
+}
+
+#-------------------------------------------------------------------
+
=head2 handlesRecurring ()
Returns 0. Should be overridden to return 1 by any subclasses that can handle recurring payments.
diff --git a/lib/WebGUI/Shop/PayDriver/ITransact.pm b/lib/WebGUI/Shop/PayDriver/ITransact.pm
index cc3acea86..5af074c05 100644
--- a/lib/WebGUI/Shop/PayDriver/ITransact.pm
+++ b/lib/WebGUI/Shop/PayDriver/ITransact.pm
@@ -39,198 +39,6 @@ sub _generateCancelRecurXml {
return $xml;
}
-#-------------------------------------------------------------------
-sub _monthYear {
- my $session = shift;
- my $form = $session->form;
-
- tie my %months, "Tie::IxHash";
- tie my %years, "Tie::IxHash";
- %months = map { sprintf( '%02d', $_ ) => sprintf( '%02d', $_ ) } 1 .. 12;
- %years = map { $_ => $_ } 2004 .. 2099;
-
- my $monthYear =
- WebGUI::Form::selectBox( $session, {
- name => 'expMonth',
- options => \%months,
- value => [ $form->process("expMonth") ]
- })
- . " / "
- . WebGUI::Form::selectBox( $session, {
- name => 'expYear',
- options => \%years,
- value => [ $form->process("expYear") ]
- });
-
- return $monthYear;
-}
-
-#-------------------------------------------------------------------
-sub _resolveRecurRecipe {
- my $self = shift;
- my $duration = shift;
-
- my %resolve = (
- Weekly => 'weekly',
- BiWeekly => 'biweekly',
- FourWeekly => 'fourweekly',
- Monthly => 'monthly',
- Quarterly => 'quarterly',
- HalfYearly => 'halfyearly',
- Yearly => 'yearly',
- );
-
- # TODO: Throw exception
- return $resolve{ $duration };
-}
-
-
-#-------------------------------------------------------------------
-
-=head2 doXmlRequest ( xml [ isAdministrative ] )
-
-Post an xml request to the ITransact backend. Returns a LWP::UserAgent response object.
-
-=head3 xml
-
-The xml string. Must contain a valid xml header.
-
-=head3 isGatewayInterface
-
-Determines what kind of request the xml is. For GatewayRequests set this value to 1. For SaleRequests set to 0 or
-undef.
-
-=cut
-
-sub doXmlRequest {
- my $self = shift;
- my $xml = shift;
- my $isGatewayInterface = shift;
-
- # Figure out which cgi script we should post the XML to.
- my $xmlTransactionScript = $isGatewayInterface
- ? 'https://secure.paymentclearing.com/cgi-bin/rc/xmltrans2.cgi'
- : 'https://secure.paymentclearing.com/cgi-bin/rc/xmltrans.cgi'
- ;
- # Set up LWP
- my $userAgent = LWP::UserAgent->new;
- $userAgent->env_proxy;
- $userAgent->agent("WebGUI");
-
- # Create a request and stuff the xml in it
- my $request = HTTP::Request->new( POST => $xmlTransactionScript );
- $request->content_type( 'application/x-www-form-urlencoded' );
- $request->content( 'xml='.$xml );
-
- # Do the request
- my $response = $userAgent->request($request);
-
- return $response;
-}
-
-#-------------------------------------------------------------------
-
-=head2 cancelRecurringPayment ( transaction )
-
-Cancels a recurring transaction. Returns an array containing ( isSuccess, gatewayStatus, gatewayError).
-
-=head3 transaction
-
-The instanciated recurring transaction object.
-
-=cut
-
-sub cancelRecurringPayment {
- my $self = shift;
- my $transaction = shift;
- my $session = $self->session;
- #### TODO: Throw exception
-
- # Get the payment definition XML
- my $xml = $self->_generateCancelRecurXml( $transaction );
- $session->errorHandler->info("XML Request: $xml");
-
- # Post the xml to ITransact
- my $response = $self->doXmlRequest( $xml, 1 );
-
- # Process response
- if ($response->is_success) {
- # We got some XML back from iTransact, now parse it.
- $session->errorHandler->info('Starting request');
- my $transactionResult = XMLin( $response->content );
- unless (defined $transactionResult->{ RecurUpdateResponse }) {
- # GatewayFailureResponse: This means the xml is invalid or has the wrong mime type
- $session->errorHandler->info( "GatewayFailureResponse: result: [" . $response->content . "]" );
- return(
- 0,
- $transactionResult->{ Status },
- $transactionResult->{ ErrorMessage } . ' Category: ' . $transactionResult->{ ErrorCategory }
- );
- } else {
- # RecurUpdateResponse: We have succesfully sent the XML and it was correct. Note that this doesn't mean
- # that the cancellation has succeeded. It only has if Status is set to OK and the remaining terms is 0.
- $session->errorHandler->info( "RecurUpdateResponse: result: [" . $response->content . "]" );
- my $transactionData = $transactionResult->{ RecurUpdateResponse };
-
- my $status = $transactionData->{ Status };
- my $errorMessage = $transactionData->{ ErrorMessage };
- my $errorCategory = $transactionData->{ ErrorCategory };
- my $remainingTerms = $transactionData->{ RecurDetails }->{ RemReps };
-
- # Uppercase the status b/c the documentation is not clear on the case.
- my $isSuccess = uc( $status ) eq 'OK' && $remainingTerms == 0;
-
- return ( $isSuccess, $status, "$errorMessage Category: $errorCategory" );
- }
- } else {
- # Connection Error
- $session->errorHandler->info("Connection error");
-
- return ( 0, undef, 'ConnectionError', $response->status_line );
- }
-}
-
-#-------------------------------------------------------------------
-sub definition {
- my $class = shift;
- my $session = shift;
- my $definition = shift;
-
- my $i18n = WebGUI::International->new($session, 'PayDriver_ITransact');
-
- tie my %fields, 'Tie::IxHash';
- %fields = (
- vendorId => {
- fieldType => 'text',
- label => $i18n->echo('vendorId'),
- hoverHelp => $i18n->echo('vendorId help'),
- },
- password => {
- fieldType => 'password',
- label => $i18n->echo('password'),
- hoverHelp => $i18n->echo('password help'),
- },
- useCVV2 => {
- fieldType => 'yesNo',
- label => $i18n->echo('use cvv2'),
- hoverHelp => $i18n->echo('use cvv2 help'),
- },
- emailMessage => {
- fieldType => 'textarea',
- label => $i18n->echo('emailMessage'),
- hoverHelp => $i18n->echo('emailMessage help'),
- },
- # readonly stuff from old plugin here?
- );
-
- push @{ $definition }, {
- name => $i18n->echo('Itransact'),
- properties => \%fields,
- };
-
- return $class->SUPER::definition($session, $definition);
-}
-
#-------------------------------------------------------------------
sub _generatePaymentRequestXML {
my $self = shift;
@@ -357,6 +165,266 @@ sub _generatePaymentRequestXML {
return $xml;
}
+#-------------------------------------------------------------------
+sub _monthYear {
+ my $session = shift;
+ my $form = $session->form;
+
+ tie my %months, "Tie::IxHash";
+ tie my %years, "Tie::IxHash";
+ %months = map { sprintf( '%02d', $_ ) => sprintf( '%02d', $_ ) } 1 .. 12;
+ %years = map { $_ => $_ } 2004 .. 2099;
+
+ my $monthYear =
+ WebGUI::Form::selectBox( $session, {
+ name => 'expMonth',
+ options => \%months,
+ value => [ $form->process("expMonth") ]
+ })
+ . " / "
+ . WebGUI::Form::selectBox( $session, {
+ name => 'expYear',
+ options => \%years,
+ value => [ $form->process("expYear") ]
+ });
+
+ return $monthYear;
+}
+
+#-------------------------------------------------------------------
+sub _resolveRecurRecipe {
+ my $self = shift;
+ my $duration = shift;
+
+ my %resolve = (
+ Weekly => 'weekly',
+ BiWeekly => 'biweekly',
+ FourWeekly => 'fourweekly',
+ Monthly => 'monthly',
+ Quarterly => 'quarterly',
+ HalfYearly => 'halfyearly',
+ Yearly => 'yearly',
+ );
+
+ # TODO: Throw exception
+ return $resolve{ $duration };
+}
+
+
+
+#-------------------------------------------------------------------
+
+=head2 cancelRecurringPayment ( transaction )
+
+Cancels a recurring transaction. Returns an array containing ( isSuccess, gatewayStatus, gatewayError).
+
+=head3 transaction
+
+The instanciated recurring transaction object.
+
+=cut
+
+sub cancelRecurringPayment {
+ my $self = shift;
+ my $transaction = shift;
+ my $session = $self->session;
+ #### TODO: Throw exception
+
+ # Get the payment definition XML
+ my $xml = $self->_generateCancelRecurXml( $transaction );
+ $session->errorHandler->info("XML Request: $xml");
+
+ # Post the xml to ITransact
+ my $response = $self->doXmlRequest( $xml, 1 );
+
+ # Process response
+ if ($response->is_success) {
+ # We got some XML back from iTransact, now parse it.
+ $session->errorHandler->info('Starting request');
+ my $transactionResult = XMLin( $response->content );
+ unless (defined $transactionResult->{ RecurUpdateResponse }) {
+ # GatewayFailureResponse: This means the xml is invalid or has the wrong mime type
+ $session->errorHandler->info( "GatewayFailureResponse: result: [" . $response->content . "]" );
+ return(
+ 0,
+ $transactionResult->{ Status },
+ $transactionResult->{ ErrorMessage } . ' Category: ' . $transactionResult->{ ErrorCategory }
+ );
+ } else {
+ # RecurUpdateResponse: We have succesfully sent the XML and it was correct. Note that this doesn't mean
+ # that the cancellation has succeeded. It only has if Status is set to OK and the remaining terms is 0.
+ $session->errorHandler->info( "RecurUpdateResponse: result: [" . $response->content . "]" );
+ my $transactionData = $transactionResult->{ RecurUpdateResponse };
+
+ my $status = $transactionData->{ Status };
+ my $errorMessage = $transactionData->{ ErrorMessage };
+ my $errorCategory = $transactionData->{ ErrorCategory };
+ my $remainingTerms = $transactionData->{ RecurDetails }->{ RemReps };
+
+ # Uppercase the status b/c the documentation is not clear on the case.
+ my $isSuccess = uc( $status ) eq 'OK' && $remainingTerms == 0;
+
+ return ( $isSuccess, $status, "$errorMessage Category: $errorCategory" );
+ }
+ } else {
+ # Connection Error
+ $session->errorHandler->info("Connection error");
+
+ return ( 0, undef, 'ConnectionError', $response->status_line );
+ }
+}
+
+#-------------------------------------------------------------------
+sub checkRecurringTransaction {
+ my $self = shift;
+ my $xid = shift;
+ my $expectedAmount = shift;
+ my $session = $self->session;
+
+ my $xmlStructure = {
+ GatewayInterface => {
+ VendorIdentification => {
+ VendorId => $self->get('vendorId'),
+ VendorPassword => $self->get('password'),
+ HomePage => ,
+ },
+ RecurDetails => {
+ OperiationXID => $xid,
+ },
+ }
+ };
+
+ my $xml =
+ ''
+ . XMLout( $xmlStructure,
+ NoAttr => 1,
+ KeepRoot => 1,
+ KeyAttr => [],
+ );
+
+ my $response = $self->doXmlRequest( $xml, 1 );
+
+ if ($response->is_success) {
+ $session->errorHandler->info("Check recurring postback response: [".$response->content."]");
+ # We got some XML back from iTransact, now parse it.
+ my $transactionResult = XMLin( $response->content || '