fix certain problems with third-party payment, #23579
[freeside.git] / FS / FS / agent.pm
index 3794d3f..0bb7561 100644 (file)
@@ -1,19 +1,17 @@
 package FS::agent;
+use base qw( FS::m2m_Common FS::m2name_Common FS::Record );
 
 use strict;
 use vars qw( @ISA );
-#use Crypt::YAPassGen;
 use Business::CreditCard 0.28;
 use FS::Record qw( dbh qsearch qsearchs );
 use FS::cust_main;
 use FS::cust_pkg;
-use FS::agent_type;
 use FS::reg_code;
+use FS::agent_payment_gateway;
 use FS::TicketSystem;
 use FS::Conf;
 
-@ISA = qw( FS::m2m_Common FS::Record );
-
 =head1 NAME
 
 FS::agent - Object methods for agent records
@@ -158,13 +156,6 @@ sub check {
 
 Returns the FS::agent_type object (see L<FS::agent_type>) for this agent.
 
-=cut
-
-sub agent_type {
-  my $self = shift;
-  qsearchs( 'agent_type', { 'typenum' => $self->typenum } );
-}
-
 =item agent_cust_main
 
 Returns the FS::cust_main object (see L<FS::cust_main>), if any, for this
@@ -177,6 +168,24 @@ sub agent_cust_main {
   qsearchs( 'cust_main', { 'custnum' => $self->agent_custnum } );
 }
 
+=item agent_currency
+
+Returns the FS::agent_currency objects (see L<FS::agent_currency>), if any, for
+this agent.
+
+=item agent_currency_hashref
+
+Returns a hash references of supported additional currencies for this agent.
+
+=cut
+
+sub agent_currency_hashref {
+  my $self = shift;
+  +{ map { $_->currency => 1 }
+       $self->agent_currency
+   };
+}
+
 =item pkgpart_hashref
 
 Returns a hash reference.  The keys of the hash are pkgparts.  The value is
@@ -206,7 +215,8 @@ sub ticketing_queue {
 
 Returns a payment gateway object (see L<FS::payment_gateway>) for this agent.
 
-Currently available options are I<nofatal>, I<invnum>, I<method>, and I<payinfo>.
+Currently available options are I<nofatal>, I<invnum>, I<method>, 
+I<payinfo>, and I<thirdparty>.
 
 If I<nofatal> is set, and no gateway is available, then the empty string
 will be returned instead of throwing a fatal exception.
@@ -216,15 +226,58 @@ an attempt will be made to select a gateway suited for the taxes paid on
 the invoice.
 
 The I<method> and I<payinfo> options can be used to influence the choice
-as well.  Presently only 'CC' and 'ECHECK' methods are meaningful.
+as well.  Presently only 'CC', 'ECHECK', and 'PAYPAL' methods are meaningful.
 
 When the I<method> is 'CC' then the card number in I<payinfo> can direct
 this routine to route to a gateway suited for that type of card.
 
+If I<thirdparty> is set, the defined self-service payment gateway will 
+be returned.
+
 =cut
 
 sub payment_gateway {
   my ( $self, %options ) = @_;
+  
+  my $conf = new FS::Conf;
+
+  if ( $options{thirdparty} ) {
+    # still a kludge, but it gets the job done
+    # and the 'cardtype' semantics don't really apply to thirdparty
+    # gateways because we have to choose a gateway without ever 
+    # seeing the card number
+    my $gatewaynum =
+      $conf->config('selfservice-payment_gateway', $self->agentnum);
+    my $gateway;
+    $gateway = FS::payment_gateway->by_key($gatewaynum) if $gatewaynum;
+    return $gateway if $gateway;
+
+    # a little less kludgey than the above, and allows PayPal to coexist 
+    # with credit card gateways
+    my $is_paypal = { op => '!=', value => 'PayPal' };
+    if ( uc($options{method}) eq 'PAYPAL' ) {
+      $is_paypal = 'PayPal';
+    }
+
+    $gateway = qsearchs({
+        table     => 'payment_gateway',
+        addl_from => ' JOIN agent_payment_gateway USING (gatewaynum) ',
+        hashref   => {
+          gateway_namespace => 'Business::OnlineThirdPartyPayment',
+          gateway_module    => $is_paypal,
+          disabled          => '',
+        },
+        extra_sql => ' AND agentnum = '.$self->agentnum,
+    });
+
+    if ( $gateway ) {
+      return $gateway;
+    } elsif ( $options{'nofatal'} ) {
+      return '';
+    } else {
+      die "no third-party gateway configured\n";
+    }
+  }
 
   my $taxclass = '';
   if ( $options{invnum} ) {
@@ -246,13 +299,15 @@ sub payment_gateway {
   }
 
   #look for an agent gateway override first
-  my $cardtype;
-  if ( $options{method} && $options{method} eq 'CC' && $options{payinfo} ) {
-    $cardtype = cardtype($options{payinfo});
-  } elsif ( $options{method} && $options{method} eq 'ECHECK' ) {
-    $cardtype = 'ACH';
-  } else {
-    $cardtype = $options{method} || '';
+  my $cardtype = '';
+  if ( $options{method} ) {
+    if ( $options{method} eq 'CC' && $options{payinfo} ) {
+      $cardtype = cardtype($options{payinfo});
+    } elsif ( $options{method} eq 'ECHECK' ) {
+      $cardtype = 'ACH';
+    } else {
+      $cardtype = $options{method}
+    }
   }
 
   my $override =
@@ -270,7 +325,6 @@ sub payment_gateway {
                                            taxclass => '',              } );
 
   my $payment_gateway;
-  my $conf = new FS::Conf;
   if ( $override ) { #use a payment gateway override
 
     $payment_gateway = $override->payment_gateway;
@@ -328,6 +382,23 @@ sub payment_gateway {
   $payment_gateway;
 }
 
+=item invoice_modes
+
+Returns all L<FS::invoice_mode> objects that are valid for this agent (i.e.
+those with this agentnum or null agentnum).
+
+=cut
+
+sub invoice_modes {
+  my $self = shift;
+  qsearch( {
+      table     => 'invoice_mode',
+      hashref   => { agentnum => $self->agentnum },
+      extra_sql => ' OR agentnum IS NULL',
+      order_by  => ' ORDER BY modename',
+  } );
+}
+
 =item num_prospect_cust_main
 
 Returns the number of prospects (customers with no packages ever ordered) for
@@ -367,6 +438,29 @@ sub cust_main_sql {
   );
 }
 
+=item num_ordered_cust_main
+
+Returns the number of ordered customers for this agent (customers with packages
+ordered, but not yet billed).
+
+=cut
+
+sub num_ordered_cust_main {
+  shift->num_sql(FS::cust_main->ordered_sql);
+}
+
+=item ordered_cust_main
+
+Returns the ordered customers for this agent (customers with packages ordered,
+but not yet billed), as cust_main objects.
+
+=cut
+
+sub ordered_cust_main {
+  shift->cust_main_sql(FS::cust_main->ordered_sql);
+}
+
+
 =item num_active_cust_main
 
 Returns the number of active customers for this agent (customers with active
@@ -576,6 +670,21 @@ sub num_prepay_credit {
   $sth->fetchrow_arrayref->[0];
 }
 
+=item num_sales
+
+Returns the number of non-disabled sales people for this agent.
+
+=cut
+
+sub num_sales {
+  my $self = shift;
+  my $sth = dbh->prepare(
+    "SELECT COUNT(*) FROM sales WHERE agentnum = ?
+                                  AND ( disabled = '' OR disabled IS NULL )"
+  ) or die dbh->errstr;
+  $sth->execute($self->agentnum) or die $sth->errstr;
+  $sth->fetchrow_arrayref->[0];
+}
 
 =back