From 152dfc283805089c400a8a7f28bbf91ff84b3db0 Mon Sep 17 00:00:00 2001 From: Martin Kamerbeek Date: Wed, 28 May 2008 21:16:25 +0000 Subject: [PATCH] ITransact and other fixes and migration of payment plugins. --- docs/upgrades/upgrade_7.5.10-7.5.11.pl | 28 ++ lib/WebGUI/Shop/Pay.pm | 2 +- lib/WebGUI/Shop/PayDriver.pm | 49 +- lib/WebGUI/Shop/PayDriver/ITransact.pm | 647 ++++++++++++++----------- lib/WebGUI/i18n/English/Shop.pm | 48 ++ 5 files changed, 501 insertions(+), 273 deletions(-) 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 || ''); + + unless (defined $transactionResult->{ RecurDetailsResponse }) { + # Something went wrong. + $session->errorHandler->info("Check recurring postback failed!"); + + return 0; + } else { + $session->errorHandler->info("Check recurring postback! Response: [".$response->content."]"); + + my $data = $transactionResult->{ RecurDetailsResponse }; + + my $status = $data->{ Status }; + my $amount = $data->{ RecurDetails }->{ RecurTotal }; + + $session->errorHandler->info("Check recurring postback! Status: $status"); + if ( $amount != $expectedAmount ) { + $session->errorHandler->info( + "Check recurring postback, received amount: $amount not equal to expected amount: $expectedAmount" + ); + + return 0; + } + + return 1; + } + } else { + # Connection Error + $session->errorHandler->info("Connection error"); + + return 0; + } +} + +#------------------------------------------------------------------- +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); +} + +#------------------------------------------------------------------- + +=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; +} + #------------------------------------------------------------------- sub getButton { my $self = shift; @@ -371,6 +439,18 @@ sub getButton { return $payForm; } +#------------------------------------------------------------------- + +=head2 handlesRecurring + +Tells the commerce system that this payment plugin can handle recurring payments. + +=cut + +sub handlesRecurring { + return 1; +} + #------------------------------------------------------------------- sub processCredentials { my $self = shift; @@ -427,18 +507,6 @@ sub processCredentials { return \@error; } -#------------------------------------------------------------------- - -=head2 handlesRecurring - -Tells the commerce system that this payment plugin can handle recurring payments. - -=cut - -sub handlesRecurring { - return 1; -} - #------------------------------------------------------------------- sub processPayment { my $self = shift; @@ -449,20 +517,8 @@ sub processPayment { my $xml = $self->_generatePaymentRequestXML( $transaction ); $session->errorHandler->info("XML Request: $xml"); - # Set up LWP - my $userAgent = LWP::UserAgent->new; - $userAgent->env_proxy; - $userAgent->agent("WebGUI "); - - # Create a request and stuff the xml in it - $session->errorHandler->info('Starting request'); - my $xmlTransactionScript = 'https://secure.paymentclearing.com/cgi-bin/rc/xmltrans.cgi'; - 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); + # Send the xml to ITransact + my $response = $self->doXmlRequest( $xml ); # Process response if ($response->is_success) { @@ -501,55 +557,45 @@ sub processPayment { } } -#------------------------------------------------------------------- -sub www_processRecurringTransactionPostback { - my $self = shift; - my $session = $self->session; - my $form = $session->form; - - # Get posted data of interest - my $originatingXid = $form->process( 'orig_xid' ); - my $status = $form->process( 'status' ); - my $xid = $form->process( 'xid' ); - my $errorMessage = $form->process( 'error_message' ); - - # Fetch the original transaction - my $baseTransaction = WebGUI::Shop::Transaction->newByGatewayId( $session, $originatingXid, $self->getId ); - - # Create a new transaction for this term - my $transaction = $baseTransaction->duplicate( { - originatingTransactionId => $baseTransaction->getId, - }); - - # Check the transaction status and act accordingly - if ( uc $status eq 'OK' ) { - # The term was succesfully payed - $transaction->completePurchase( $xid, $status, $errorMessage ); - } - else { - # The term has not been payed succesfully - $transaction->denyPurchase( $xid, $status, $errorMessage ); - } - - return undef; -} - #------------------------------------------------------------------- sub www_getCredentials { - my $self = shift; - my $session = $self->session; - my $form = $session->form; - my $i18n = WebGUI::International->new($self->session, 'CommercePaymentITransact'); - my $u = WebGUI::User->new($self->session,$self->session->user->userId); + my $self = shift; + my $errors = shift; + my $session = $self->session; + my $form = $session->form; + my $i18n = WebGUI::International->new($self->session, 'CommercePaymentITransact'); + my $u = WebGUI::User->new($self->session,$self->session->user->userId); + + # Process address from address book if passed + my $addressId = $session->form->process('addressId'); + my $addressData = {}; + if ( $addressId ) { + $addressData = eval{ $self->getCart->getAddressBook->getAddress( $addressId )->get() } || {}; + } + + my $output; + + # Process form errors + if ( $errors ) { + #### TODO: i18n + $output .= $i18n->echo('The following errors occurred:') + . ''; + } + + $output .= $self->getSelectAddressButton( 'getCredentials' ); my $f = WebGUI::HTMLForm->new( $session ); $self->getDoFormTags( 'pay', $f ); - + $f->hidden( + -name => 'addressId', + -value => $addressId, + ) if $addressId; + # Address data form $f->text( -name => 'firstName', -label => $i18n->get('firstName'), - -value => $form->process("firstName") || $u->profileField('firstName'), + -value => $form->process("firstName") || $addressData->{ name } || $u->profileField('firstName'), ); $f->text( -name => 'lastName', @@ -559,32 +605,32 @@ sub www_getCredentials { $f->text( -name => 'address', -label => $i18n->get('address'), - -value => $form->process("address") || $u->profileField('homeAddress'), + -value => $form->process("address") || $addressData->{ address1 } || $u->profileField('homeAddress'), ); $f->text( -name => 'city', -label => $i18n->get('city'), - -value => $form->process("city") || $u->profileField('homeCity'), + -value => $form->process("city") || $addressData->{ city } || $u->profileField('homeCity'), ); $f->text( -name => 'state', -label => $i18n->get('state'), - -value => $form->process("state") || $u->profileField('homeState'), + -value => $form->process("state") || $addressData->{ state } || $u->profileField('homeState'), ); $f->zipcode( -name => 'zipcode', -label => $i18n->get('zipcode'), - -value => $form->process("zipcode") || $u->profileField('homeZip'), + -value => $form->process("zipcode") || $addressData->{ code } || $u->profileField('homeZip'), ); $f->country( -name => "country", -label => $i18n->get("country"), - -value => ($form->process("country",'country') || $u->profileField("homeCountry") || 'United States'), + -value => ($form->process("country",'country') || $addressData->{ country } || $u->profileField("homeCountry") || 'United States'), ); $f->phone( -name => "phone", -label => $i18n->get("phone"), - -value => $form->process("phone",'phone') || $u->profileField("homePhone"), + -value => $form->process("phone",'phone') || $addressData->{ phoneNumber } || $u->profileField("homePhone"), ); $f->email( -name => 'email', @@ -611,13 +657,15 @@ sub www_getCredentials { -value => 'Checkout', ); - return $session->style->userStyle($f->print); + $output .= $f->print; + return $session->style->userStyle( $output ); } #------------------------------------------------------------------- sub www_pay { - my $self = shift; - my $session = $self->session; + my $self = shift; + my $session = $self->session; + my $addressId = $session->form->process( 'addressId' ) || undef; # Check whether the user filled in the checkout form and process those. my $credentialsErrors = $self->processCredentials; @@ -626,11 +674,70 @@ sub www_pay { return $self->www_getCredentials( $credentialsErrors ) if $credentialsErrors; # Payment time! - my $transaction = $self->processTransaction; + my $transaction = $self->processTransaction( $addressId ); if ($transaction->get('isSuccessful')) { - return $transaction->thankYou(); + return $transaction->thankYou(); } - return $self->displayPaymentError($transaction); + + # Payment has failed... + return $self->displayPaymentError($transaction); +} + +#------------------------------------------------------------------- +sub www_processRecurringTransactionPostback { + my $self = shift; + my $session = $self->session; + my $form = $session->form; + + # Get posted data of interest + my $originatingXid = $form->process( 'orig_xid' ); + my $status = $form->process( 'status' ); + my $xid = $form->process( 'xid' ); + my $errorMessage = $form->process( 'error_message' ); + + # Fetch the original transaction + my $baseTransaction = WebGUI::Shop::Transaction->newByGatewayId( $session, $originatingXid, $self->getId ); + + #---- Check the validity of the request ------- + # First check whether the original transaction actualy exists + unless ( $baseTransaction ) { + $session->errorHandler->warn->("Check recurring postback: No base transction for XID: [$originatingXid]"); + return; + } + + # Secondly check if the postback is coming from secure.paymentclearing.com + # This will most certainly fail on mod_proxied webgui instances +# unless ( $ENV{ HTTP_HOST } eq 'secure.paymentclearing.com') { +# $session->errorHandler->info('ITransact Recurring Payment Postback is coming from host: ['.$ENV{ HTTP_HOST }.']'); +# return; +# } + + # Third, check if the new xid exists and if the amount is correct. + my $expectedAmount = sprintf("%.2f", + $baseTransaction->get('amount') + $baseTransaction->get('taxes') + $baseTransaction->get('shippingPrice') ); + + unless ( $self->checkRecurringTransaction( $xid, $expectedAmount ) ) { + $session->errorHandler->warn('Check recurring postback: transaction check failed.'); + #return; + } + #---- Passed all test, continue --------------- + + # Create a new transaction for this term + my $transaction = $baseTransaction->duplicate( { + originatingTransactionId => $baseTransaction->getId, + }); + + # Check the transaction status and act accordingly + if ( uc $status eq 'OK' ) { + # The term was succesfully payed + $transaction->completePurchase( $xid, $status, $errorMessage ); + } + else { + # The term has not been payed succesfully + $transaction->denyPurchase( $xid, $status, $errorMessage ); + } + + return undef; } 1; diff --git a/lib/WebGUI/i18n/English/Shop.pm b/lib/WebGUI/i18n/English/Shop.pm index 64c2fa423..fcb63bda6 100644 --- a/lib/WebGUI/i18n/English/Shop.pm +++ b/lib/WebGUI/i18n/English/Shop.pm @@ -843,6 +843,54 @@ our $I18N = { context => q|The label for the add to cart button.| }, +'weekly' => { + message => q|Week|, + lastUpdated => 0, + context => q|Period name for a weekly subscription.| + }, + + + 'biweekly' => { + message => q|Two weeks|, + lastUpdated => 0, + context => q|Period name for a biweekly subscription.| + }, + + + 'fourweekly' => { + message => q|Four weeks|, + lastUpdated => 0, + context => q|Period name for a four weekly subscription.| + }, + + + 'monthly' => { + message => q|Month|, + lastUpdated => 0, + context => q|Period name for a monthly subscription.| + }, + + + 'quarterly' => { + message => q|Three months|, + lastUpdated => 0, + context => q|Period name for a Quarterly subscription.| + }, + + + 'halfyearly' => { + message => q|Half year|, + lastUpdated => 0, + context => q|Period name for a semi yearly subscription.| + }, + + + 'yearly' => { + message => q|Year|, + lastUpdated => 0, + context => q|Period name for a yearly subscription.| + }, + }; 1;