X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2Fpayment_gateway.pm;h=3500bf9bcf29215a2cbdb349fe5eef20218d5546;hp=fac738499df683e7cf892ab455fba70523d7ae23;hb=dc83512c36dc6bea2585abada4f88d714c600e55;hpb=a6fe07e49e3fc12169e801b1ed6874c3a5bd8500 diff --git a/FS/FS/payment_gateway.pm b/FS/FS/payment_gateway.pm index fac738499..3500bf9bc 100644 --- a/FS/FS/payment_gateway.pm +++ b/FS/FS/payment_gateway.pm @@ -1,12 +1,10 @@ package FS::payment_gateway; +use base qw( FS::option_Common ); use strict; -use vars qw( @ISA $me $DEBUG ); -use FS::Record qw( qsearch qsearchs dbh ); -use FS::option_Common; -use FS::agent_payment_gateway; +use vars qw( $me $DEBUG ); +use FS::Record qw( qsearch dbh ); #qw( qsearch qsearchs dbh ); -@ISA = qw( FS::option_Common ); $me = '[ FS::payment_gateway ]'; $DEBUG=0; @@ -41,7 +39,7 @@ currently supported: =item gateway_namespace - Business::OnlinePayment, Business::OnlineThirdPartyPayment, or Business::BatchPayment -=item gateway_module - Business::OnlinePayment:: module name +=item gateway_module - Business::OnlinePayment:: (or other) module name =item gateway_username - payment gateway username @@ -51,6 +49,14 @@ currently supported: =item disabled - Disabled flag, empty or 'Y' +=item gateway_callback_url - For ThirdPartyPayment only, set to the URL that +the user should be redirected to on a successful payment. This will be sent +as a transaction parameter named "return_url". + +=item gateway_cancel_url - For ThirdPartyPayment only, set to the URL that +the user should be redirected to if they cancel the transaction. This will +be sent as a transaction parameter named "cancel_url". + =item auto_resolve_status - For BatchPayment only, set to 'approve' to auto-approve unresolved payments after some number of days, 'reject' to auto-decline them, or null to do nothing. @@ -128,6 +134,7 @@ sub check { || $self->ut_textn('gateway_username') || $self->ut_anything('gateway_password') || $self->ut_textn('gateway_callback_url') # a bit too permissive + || $self->ut_textn('gateway_cancel_url') || $self->ut_enum('disabled', [ '', 'Y' ] ) || $self->ut_enum('auto_resolve_status', [ '', 'approve', 'reject' ]) || $self->ut_numbern('auto_resolve_days') @@ -152,8 +159,8 @@ sub check { } # this little kludge mimics FS::CGI::popurl - $self->gateway_callback_url($self->gateway_callback_url. '/') - if ( $self->gateway_callback_url && $self->gateway_callback_url !~ /\/$/ ); + #$self->gateway_callback_url($self->gateway_callback_url. '/') + # if ( $self->gateway_callback_url && $self->gateway_callback_url !~ /\/$/ ); $self->SUPER::check; } @@ -162,13 +169,6 @@ sub check { Returns any agent overrides for this payment gateway. -=cut - -sub agent_payment_gateway { - my $self = shift; - qsearch('agent_payment_gateway', { 'gatewaynum' => $self->gatewaynum } ); -} - =item disable Disables this payment gateway: deletes all associated agent_payment_gateway @@ -219,7 +219,7 @@ Returns a semi-friendly label for the gateway. sub label { my $self = shift; $self->gatewaynum . ': ' . - $self->gateway_username . '@' . + ($self->gateway_username ? $self->gateway_username . '@' : '') . $self->gateway_module } @@ -268,9 +268,12 @@ sub batch_processor { eval "use Business::BatchPayment;"; die "couldn't load Business::BatchPayment: $@" if $@; - my $conf = new FS::Conf; - my $test_mode = $conf->exists('business-batchpayment-test_transaction'); - $opt{'test_mode'} = 1 if $test_mode; + #false laziness with processor + foreach (qw(username password)) { + if (length($self->get("gateway_$_"))) { + $opt{$_} = $self->get("gateway_$_"); + } + } my $module = $self->gateway_module; my $processor = eval { @@ -280,11 +283,159 @@ sub batch_processor { if $@; die "$module does not support test mode" - if $test_mode and not $processor->does('Business::BatchPayment::TestMode'); + if $opt{'test_mode'} + and not $processor->does('Business::BatchPayment::TestMode'); return $processor; } +=item processor OPTIONS + +Loads the module for the processor and returns an instance of it. + +=cut + +sub processor { + local $@; + my $self = shift; + my %opt = @_; + foreach (qw(action username password)) { + if (length($self->get("gateway_$_"))) { + $opt{$_} = $self->get("gateway_$_"); + } + } + $opt{'return_url'} = $self->gateway_callback_url; + $opt{'cancel_url'} = $self->gateway_cancel_url; + + my $conf = new FS::Conf; + my $test_mode = $conf->exists('business-batchpayment-test_transaction'); + $opt{'test_mode'} = 1 if $test_mode; + + my $namespace = $self->gateway_namespace; + eval "use $namespace"; + die "couldn't load $namespace: $@" if $@; + + if ( $namespace eq 'Business::BatchPayment' ) { + # at some point we can merge these, but there's enough special behavior... + return $self->batch_processor(%opt); + } else { + return $namespace->new( $self->gateway_module, $self->options, %opt ); + } +} + +=item default_gateway OPTIONS + +Class method. + +Returns default gateway (from business-onlinepayment conf) as a payment_gateway object. + +Accepts options + +conf - existing conf object + +nofatal - return blank instead of dying if no default gateway is configured + +method - if set to CHEK or ECHECK, returns object for business-onlinepayment-ach if available + +Before using this, be sure you wouldn't rather be using L or, +more likely, L. + +=cut + +# the standard settings from the config could be moved to a null agent +# agent_payment_gateway referenced payment_gateway + +sub default_gateway { + my ($self,%options) = @_; + + $options{'conf'} ||= new FS::Conf; + my $conf = $options{'conf'}; + + unless ( $conf->exists('business-onlinepayment') ) { + if ( $options{'nofatal'} ) { + return ''; + } else { + die "Real-time processing not enabled\n"; + } + } + + #load up config + my $bop_config = 'business-onlinepayment'; + $bop_config .= '-ach' + if ( $options{method} + && $options{method} =~ /^(ECHECK|CHEK)$/ + && $conf->exists($bop_config. '-ach') + ); + my ( $processor, $login, $password, $action, @bop_options ) = + $conf->config($bop_config); + $action ||= 'normal authorization'; + pop @bop_options if scalar(@bop_options) % 2 && $bop_options[-1] =~ /^\s*$/; + die "No real-time processor is enabled - ". + "did you set the business-onlinepayment configuration value?\n" + unless $processor; + + my $payment_gateway = new FS::payment_gateway; + $payment_gateway->gateway_namespace( $conf->config('business-onlinepayment-namespace') || + 'Business::OnlinePayment'); + $payment_gateway->gateway_module($processor); + $payment_gateway->gateway_username($login); + $payment_gateway->gateway_password($password); + $payment_gateway->gateway_action($action); + $payment_gateway->set('options', [ @bop_options ]); + return $payment_gateway; +} + +=item by_key_with_namespace GATEWAYNUM + +Like usual by_key, but makes sure namespace is set, +and dies if not found. + +=cut + +sub by_key_with_namespace { + my $self = shift; + my $payment_gateway = $self->by_key(@_); + die "payment_gateway not found" + unless $payment_gateway; + $payment_gateway->gateway_namespace('Business::OnlinePayment') + unless $payment_gateway->gateway_namespace; + return $payment_gateway; +} + +=item by_key_or_default OPTIONS + +Either returns the gateway specified by option gatewaynum, or the default gateway. + +Accepts the same options as L. + +Also ensures that the gateway_namespace has been set. + +=cut + +sub by_key_or_default { + my ($self,%options) = @_; + + if ($options{'gatewaynum'}) { + return $self->by_key_with_namespace($options{'gatewaynum'}); + } else { + return $self->default_gateway(%options); + } +} + +# if it weren't for the way gateway_namespace default is set, this method would not be necessary +# that should really go in check() with an accompanying upgrade, so we could just use qsearch safely, +# but currently short on time to test deeper changes... +# +# if no default gateway is set and nofatal is passed, first value returned is blank string +sub all_gateways { + my ($self,%options) = @_; + my @out; + foreach my $gatewaynum ('',( map {$_->gatewaynum} qsearch('payment_gateway') )) { + push @out, $self->by_key_or_default( %options, gatewaynum => $gatewaynum ); + } + return @out; +} + # _upgrade_data # # Used by FS::Upgrade to migrate to a new database.