diff options
Diffstat (limited to 'FS')
| -rw-r--r-- | FS/FS/CGI.pm | 33 | ||||
| -rw-r--r-- | FS/FS/ClientAPI/Agent.pm | 113 | ||||
| -rw-r--r-- | FS/FS/ClientAPI/MyAccount.pm | 79 | ||||
| -rw-r--r-- | FS/FS/ClientAPI/Signup.pm | 64 | ||||
| -rw-r--r-- | FS/FS/agent.pm | 104 | ||||
| -rw-r--r-- | FS/FS/cust_main.pm | 130 | 
6 files changed, 488 insertions, 35 deletions
| diff --git a/FS/FS/CGI.pm b/FS/FS/CGI.pm index a3286299b..1ddc62c7a 100644 --- a/FS/FS/CGI.pm +++ b/FS/FS/CGI.pm @@ -294,6 +294,8 @@ sub small_custview {      or die "unknown custnum $arg";    my $html = 'Customer #<B>'. $cust_main->custnum. '</B>'. +    ' - <B><FONT COLOR="'. $cust_main->statuscolor. '">'. +    ucfirst($cust_main->status). '</FONT></B>'.      ntable('#e8e8e8'). '<TR><TD>'. ntable("#cccccc",2).      '<TR><TD ALIGN="right" VALIGN="top">Billing<BR>Address</TD><TD BGCOLOR="#ffffff">'.      $cust_main->getfield('last'). ', '. $cust_main->first. '<BR>'; @@ -305,6 +307,20 @@ sub small_custview {    $html .= $cust_main->country. '<BR>'      if $cust_main->country && $cust_main->country ne $countrydefault; +  $html .= '</TD></TR><TR><TD></TD><TD BGCOLOR="#ffffff">'; +  if ( $cust_main->daytime && $cust_main->night ) { +    use FS::Msgcat; +    $html .= ( FS::Msgcat::_gettext('daytime') || 'Day' ). +             ' '. $cust_main->daytime. +             '<BR>'. ( FS::Msgcat::_gettext('night') || 'Night' ). +             ' '. $cust_main->night; +  } elsif ( $cust_main->daytime || $cust_main->night ) { +    $html .= $cust_main->daytime || $cust_main->night; +  } +  if ( $cust_main->fax ) { +    $html .= '<BR>Fax '. $cust_main->fax; +  } +    $html .= '</TD></TR></TABLE></TD>';    if ( defined $cust_main->dbdef_table->column('ship_last') ) { @@ -327,6 +343,23 @@ sub small_custview {        if $cust_main->get("${pre}country")           && $cust_main->get("${pre}country") ne $countrydefault; +    $html .= '</TD></TR><TR><TD></TD><TD BGCOLOR="#ffffff">'; + +    if ( $cust_main->get("${pre}daytime") && $cust_main->get("${pre}night") ) { +      use FS::Msgcat; +      $html .= ( FS::Msgcat::_gettext('daytime') || 'Day' ). +               ' '. $cust_main->get("${pre}daytime"). +               '<BR>'. ( FS::Msgcat::_gettext('night') || 'Night' ). +               ' '. $cust_main->get("${pre}night"); +    } elsif ( $cust_main->get("${pre}daytime") +              || $cust_main->get("${pre}night") ) { +      $html .= $cust_main->get("${pre}daytime") +               || $cust_main->get("${pre}night"); +    } +    if ( $cust_main->get("${pre}fax") ) { +      $html .= '<BR>Fax '. $cust_main->get("${pre}fax"); +    } +      $html .= '</TD></TR></TABLE></TD>';    } diff --git a/FS/FS/ClientAPI/Agent.pm b/FS/FS/ClientAPI/Agent.pm new file mode 100644 index 000000000..212faaa6b --- /dev/null +++ b/FS/FS/ClientAPI/Agent.pm @@ -0,0 +1,113 @@ +package FS::ClientAPI::Agent; + +#some false laziness w/MyAccount + +use strict; +use vars qw($cache); +use Digest::MD5 qw(md5_hex); +use Cache::SharedMemoryCache; #store in db? +use FS::Record qw(qsearchs); # qsearch); +use FS::agent; + +use FS::ClientAPI; +FS::ClientAPI->register_handlers( +  'Agent/agent_login'          => \&agent_login, +  'Agent/agent_info'           => \&agent_info, +  'Agent/agent_list_customers' => \&agent_list_customers, +); + +#store in db? +my $cache = new Cache::SharedMemoryCache( { +   'namespace' => 'FS::ClientAPI::Agent', +} ); + +sub agent_login { +  my $p = shift; + +  #don't allow a blank login to first unconfigured agent with no user/pass +  return { error => 'Must specify your reseller username and password.' } +    unless length($p->{'username'}) && length($p->{'password'}); + +  my $agent = qsearchs( 'agent', { +    'username'  => $p->{'username'}, +    '_password' => $p->{'password'}, +  } ); + +  unless ( $agent ) { return { error => 'Incorrect password.' } } + +  my $session = {  +    'agentnum' => $agent->agentnum, +    'agent'    => $agent->agent, +  }; + +  my $session_id; +  do { +    $session_id = md5_hex(md5_hex(time(). {}. rand(). $$)) +  } until ( ! defined $cache->get($session_id) ); #just in case + +  $cache->set( $session_id, $session, '1 hour' ); + +  { 'error'      => '', +    'session_id' => $session_id, +  }; +} + +sub agent_info { +  my $p = shift; + +  my $session = $cache->get($p->{'session_id'}) +    or return { 'error' => "Can't resume session" }; #better error message + +  #my %return; + +  my $agentnum = $session->{'agentnum'}; + +  my $agent = qsearchs( 'agent', { 'agentnum' => $agentnum } ) +    or return { 'error' => "unknown agentnum $agentnum" }; + +  { 'error'        => '', +    'agentnum'     => $agentnum, +    'agent'        => $agent->agent, +    'num_prospect' => $agent->num_prospect_cust_main, +    'num_active'   => $agent->num_active_cust_main, +    'num_susp'     => $agent->num_susp_cust_main, +    'num_cancel'   => $agent->num_cancel_cust_main, +    #%return, +  }; + +} + +sub agent_list_customers { +  my $p = shift; + +  my $session = $cache->get($p->{'session_id'}) +    or return { 'error' => "Can't resume session" }; #better error message + +  #my %return; + +  my $agentnum = $session->{'agentnum'}; + +  my $agent = qsearchs( 'agent', { 'agentnum' => $agentnum } ) +    or return { 'error' => "unknown agentnum $agentnum" }; + +  my @cust_main = (); + +  warn $p->{'susp'}; + +  push @cust_main, +    map $agent->$_(), map $_.'_cust_main', +      grep $p->{$_}, qw( prospect active susp cancel ); + +  { customers => [ map { +                         my $cust_main = $_; +                         my $hashref = $cust_main->hashref; +                         $hashref->{$_} = $cust_main->$_() +                           foreach qw(name status statuscolor); +                         delete $hashref->{$_} foreach qw( payinfo paycvv ); +                         $hashref; +                   } @cust_main +                 ], +  } + +} + diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index 77c1fc889..271d0c2cc 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -25,6 +25,7 @@ FS::ClientAPI->register_handlers(    'MyAccount/customer_info'    => \&customer_info,    'MyAccount/edit_info'        => \&edit_info,    'MyAccount/invoice'          => \&invoice, +  'MyAccount/list_invoices'    => \&list_invoices,    'MyAccount/cancel'           => \&cancel,    'MyAccount/payment_info'     => \&payment_info,    'MyAccount/process_payment'  => \&process_payment, @@ -86,16 +87,31 @@ sub login {  sub customer_info {    my $p = shift; -  my $session = $cache->get($p->{'session_id'}) -    or return { 'error' => "Can't resume session" }; #better error message - -  my %return; -  my $custnum = $session->{'custnum'}; +  my($session, $custnum, $context); +  if ( $p->{'session_id'} ) { +    $context = 'customer'; +    $session = $cache->get($p->{'session_id'}) +      or return { 'error' => "Can't resume session" }; #better error message +    $custnum = $session->{'custnum'}; +  } elsif ( $p->{'agent_session_id'} ) { +    $context = 'agent'; +    my $agent_cache = new Cache::SharedMemoryCache( { +      'namespace' => 'FS::ClientAPI::Agent', +    } ); +    $session = $agent_cache->get($p->{'agent_session_id'}) +      or return { 'error' => "Can't resume session" }; #better error message +    $custnum = $p->{'custnum'}; +  } else { +    return { 'error' => "Can't resume session" }; #better error message +  } +  my %return;    if ( $custnum ) { #customer record -    my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) +    my $search = { 'custnum' => $custnum }; +    $search->{'agentnum'} = $session->{'agentnum'} if $context eq 'agent'; +    my $cust_main = qsearchs('cust_main', $search )        or return { 'error' => "unknown custnum $custnum" };      $return{balance} = $cust_main->balance; @@ -357,6 +373,27 @@ sub invoice {  } +sub list_invoices { +  my $p = shift; +  my $session = $cache->get($p->{'session_id'}) +    or return { 'error' => "Can't resume session" }; #better error message + +  my $custnum = $session->{'custnum'}; + +  my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) +    or return { 'error' => "unknown custnum $custnum" }; + +  my @cust_bill = $cust_main->cust_bill; + +  return  { 'error'       => '', +            'invoices'    =>  [ map { { 'invnum' => $_->invnum, +                                        '_date'  => $_->_date, +                                      } +                                    } @cust_bill +                              ] +          }; +} +  sub cancel {    my $p = shift;    my $session = $cache->get($p->{'session_id'}) @@ -391,12 +428,30 @@ sub list_pkgs {  sub order_pkg {    my $p = shift; -  my $session = $cache->get($p->{'session_id'}) -    or return { 'error' => "Can't resume session" }; #better error message -  my $custnum = $session->{'custnum'}; +  my($session, $custnum, $context); + +  if ( $p->{'session_id'} ) { +    $context = 'customer'; +    $session = $cache->get($p->{'session_id'}) +      or return { 'error' => "Can't resume session" }; #better error message +    $custnum = $session->{'custnum'}; +  } elsif ( $p->{'agent_session_id'} ) { +    $context = 'agent'; +    my $agent_cache = new Cache::SharedMemoryCache( { +      'namespace' => 'FS::ClientAPI::Agent', +    } ); +    $session = $agent_cache->get($p->{'agent_session_id'}) +      or return { 'error' => "Can't resume session" }; #better error message +    $custnum = $p->{'custnum'}; +  } else { +    return { 'error' => "Can't resume session" }; #better error message +  } -  my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) +  my $search = { 'custnum' => $custnum }; +  $search->{'agentnum'} = $session->{'agentnum'} if $context eq 'agent'; + +  my $cust_main = qsearchs('cust_main', $search )      or return { 'error' => "unknown custnum $custnum" };    #false laziness w/ClientAPI/Signup.pm @@ -503,13 +558,13 @@ sub cancel_pkg {    my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )      or return { 'error' => "unknown custnum $custnum" }; -  my $pkgnum = $session->{'pkgnum'}; +  my $pkgnum = $p->{'pkgnum'};    my $cust_pkg = qsearchs('cust_pkg', { 'custnum' => $custnum,                                          'pkgnum'  => $pkgnum,   } )      or return { 'error' => "unknown pkgnum $pkgnum" }; -  my $error = $cust_main->cancel( 'quiet'=>1 ); +  my $error = $cust_pkg->cancel( 'quiet'=>1 );    return { 'error' => $error };  } diff --git a/FS/FS/ClientAPI/Signup.pm b/FS/FS/ClientAPI/Signup.pm index 4655b0984..2e2b80fcb 100644 --- a/FS/FS/ClientAPI/Signup.pm +++ b/FS/FS/ClientAPI/Signup.pm @@ -22,7 +22,7 @@ FS::ClientAPI->register_handlers(  );  sub signup_info { -  #my $packet = shift; +  my $packet = shift;    my $conf = new FS::Conf; @@ -87,24 +87,35 @@ sub signup_info {    }; -  if ( -    $conf->config('signup_server-default_agentnum') -    && !exists $signup_info->{'part_pkg'} #cache for performance -  ) { -    my $agentnum = $conf->config('signup_server-default_agentnum'); -    my $agent = qsearchs( 'agent', { 'agentnum' => $agentnum } ) -      or die "fatal: signup_server-default_agentnum $agentnum not found\n"; -    my $pkgpart_href = $agent->pkgpart_hashref; - -    $signup_info->{'part_pkg'} = [ -      #map { $_->hashref } -      map { { 'payby' => [ $_->payby ], %{$_->hashref} } } -        grep { $_->svcpart('svc_acct') && $pkgpart_href->{ $_->pkgpart } } -          qsearch( 'part_pkg', { 'disabled' => '' } ) -    ]; +  my $agentnum = $conf->config('signup_server-default_agentnum'); + +  my $session = ''; +  if ( exists $packet->{'session_id'} ) { +    my $cache = new Cache::SharedMemoryCache( { +      'namespace' => 'FS::ClientAPI::Agent', +    } ); +    $session = $cache->get($packet->{'session_id'}); +    if ( $session ) { +      $agentnum = $session->{'agentnum'}; +    } else { +      return { 'error' => "Can't resume session" }; #better error message +    }    } -  $signup_info; +  if ( $agentnum ) { +    $signup_info->{'part_pkg'} = $signup_info->{'agentnum2part_pkg'}{$agentnum}; +  } else { +    delete $signup_info->{'part_pkg'}; +  } + +  if ( $session ) { +    my $agent_signup_info = { %$signup_info }; +    delete $agent_signup_info->{agentnum2part_pkg}; +    $agent_signup_info->{'agent'} = $session->{'agent'}; +    $agent_signup_info; +  } else { +    $signup_info; +  }  } @@ -122,12 +133,27 @@ sub new_customer {    return { 'error' => gettext('no_access_number_selected') }      unless $packet->{'popnum'} || !scalar(qsearch('svc_acct_pop',{} )); +  my $agentnum; +  if ( exists $packet->{'session_id'} ) { +    my $cache = new Cache::SharedMemoryCache( { +      'namespace' => 'FS::ClientAPI::Agent', +    } ); +    my $session = $cache->get($packet->{'session_id'}); +    if ( $session ) { +      $agentnum = $session->{'agentnum'}; +    } else { +      return { 'error' => "Can't resume session" }; #better error message +    } +  } else { +    $agentnum = $packet->{agentnum} +                || $conf->config('signup_server-default_agentnum'); +  } +    #shares some stuff with htdocs/edit/process/cust_main.cgi... take any    # common that are still here and library them.    my $cust_main = new FS::cust_main ( {      #'custnum'          => '', -    'agentnum'      => $packet->{agentnum} -                       || $conf->config('signup_server-default_agentnum'), +    'agentnum'      => $agentnum,      'refnum'        => $packet->{refnum}                         || $conf->config('signup_server-default_refnum'), diff --git a/FS/FS/agent.pm b/FS/FS/agent.pm index 2f70d654d..7c69dfbf2 100644 --- a/FS/FS/agent.pm +++ b/FS/FS/agent.pm @@ -2,7 +2,7 @@ package FS::agent;  use strict;  use vars qw( @ISA ); -use FS::Record qw( qsearch qsearchs ); +use FS::Record qw( dbh qsearch qsearchs );  use FS::cust_main;  use FS::agent_type; @@ -164,11 +164,107 @@ sub pkgpart_hashref {    $self->agent_type->pkgpart_hashref;  } -=back +=item num_prospect_cust_main + +Returns the number of prospects (customers with no packages ever ordered) for +this agent. + +=cut + +sub num_prospect_cust_main { +  shift->num_sql(FS::cust_main->prospect_sql); +} + +sub num_sql { +  my( $self, $sql ) = @_; +  my $sth = dbh->prepare( +    "SELECT COUNT(*) FROM cust_main WHERE agentnum = ? AND $sql" +  ) or die dbh->errstr; +  $sth->execute($self->agentnum) or die $sth->errstr; +  $sth->fetchrow_arrayref->[0]; +} + +=item prospect_cust_main + +Returns the prospects (customers with no packages ever ordered) for this agent, +as cust_main objects. + +=cut + +sub prospect_cust_main { +  shift->cust_main_sql(FS::cust_main->prospect_sql); +} + +sub cust_main_sql { +  my( $self, $sql ) = @_; +  qsearch( 'cust_main', +           { 'agentnum' => $self->agentnum }, +           '', +           " AND $sql" +  ); +} + +=item num_active_cust_main + +Returns the number of active customers for this agent. + +=cut + +sub num_active_cust_main { +  shift->num_sql(FS::cust_main->active_sql); +} + +=item active_cust_main + +Returns the active customers for this agent, as cust_main objects. + +=cut -=head1 VERSION +sub active_cust_main { +  shift->cust_main_sql(FS::cust_main->active_sql); +} + +=item num_susp_cust_main + +Returns the number of suspended customers for this agent. + +=cut + +sub num_susp_cust_main { +  shift->num_sql(FS::cust_main->susp_sql); +} + +=item susp_cust_main + +Returns the suspended customers for this agent, as cust_main objects. + +=cut + +sub susp_cust_main { +  shift->cust_main_sql(FS::cust_main->susp_sql); +} -$Id: agent.pm,v 1.6 2003-09-30 15:01:46 ivan Exp $ +=item num_cancel_cust_main + +Returns the number of cancelled customer for this agent. + +=cut + +sub num_cancel_cust_main { +  shift->num_sql(FS::cust_main->cancel_sql); +} + +=item cancel_cust_main + +Returns the cancelled customers for this agent, as cust_main objects. + +=cut + +sub cancel_cust_main { +  shift->cust_main_sql(FS::cust_main->cancel_sql); +} + +=back  =head1 BUGS diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index fbd461841..07f0a34e5 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -2538,6 +2538,136 @@ sub select_for_update {    qsearch('cust_main', { 'custnum' => $self->custnum }, '*', 'FOR UPDATE' );  } +=item name + +Returns a name string for this customer, either "Company (Last, First)" or +"Last, First". + +=cut + +sub name { +  my $self = shift; +  my $name = $self->get('last'). ', '. $self->first; +  $name = $self->company. " ($name)" if $self->company; +  $name; +} + +=item status + +Returns a status string for this customer, currently: + +=over 4 + +=item prospect - No packages have ever been ordered + +=item active - One or more recurring packages is active + +=item suspended - All non-cancelled recurring packages are suspended + +=item cancelled - All recurring packages are cancelled + +=back + +=cut + +sub status { +  my $self = shift; +  for my $status (qw( prospect active suspended cancelled )) { +    my $method = $status.'_sql'; +    my $numnum = ( my $sql = $self->$method() ) =~ s/cust_main\.custnum/?/g; +    my $sth = dbh->prepare("SELECT $sql") or die dbh->errstr; +    $sth->execute( ($self->custnum) x $numnum ) or die $sth->errstr; +    return $status if $sth->fetchrow_arrayref->[0]; +  } +} + +=item statuscolor + +Returns a hex triplet color string for this customer's status. + +=cut + +my %statuscolor = ( +  'prospect'  => '000000', +  'active'    => '00CC00', +  'suspended' => 'FF9900', +  'cancelled' => 'FF0000', +); +sub statuscolor { +  my $self = shift; +  $statuscolor{$self->status}; +} + +=back + +=head1 CLASS METHODS + +=over 4 + +=item prospect_sql + +Returns an SQL expression identifying prospective cust_main records (customers +with no packages ever ordered) + +=cut + +sub prospect_sql { " +  0 = ( SELECT COUNT(*) FROM cust_pkg +          WHERE cust_pkg.custnum = cust_main.custnum +      ) +"; } + +=item active_sql + +Returns an SQL expression identifying active cust_main records. + +=cut + +sub active_sql { " +  0 < ( SELECT COUNT(*) FROM cust_pkg +          WHERE cust_pkg.custnum = cust_main.custnum +            AND ( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 ) +            AND ( cust_pkg.susp   IS NULL OR cust_pkg.susp   = 0 ) +      ) +"; } + +=item susp_sql +=item suspended_sql + +Returns an SQL expression identifying suspended cust_main records. + +=cut + +sub suspended_sql { susp_sql(@_); } +sub susp_sql { " +    0 < ( SELECT COUNT(*) FROM cust_pkg +            WHERE cust_pkg.custnum = cust_main.custnum +              AND ( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 ) +        ) +    AND 0 = ( SELECT COUNT(*) FROM cust_pkg +                WHERE cust_pkg.custnum = cust_main.custnum +                  AND ( cust_pkg.susp IS NULL OR cust_pkg.susp = 0 ) +            ) +"; } + +=item cancel_sql +=item cancelled_sql + +Returns an SQL expression identifying cancelled cust_main records. + +=cut + +sub cancelled_sql { cancel_sql(@_); } +sub cancel_sql { " +  0 < ( SELECT COUNT(*) FROM cust_pkg +          WHERE cust_pkg.custnum = cust_main.custnum +      ) +  AND 0 = ( SELECT COUNT(*) FROM cust_pkg +              WHERE cust_pkg.custnum = cust_main.custnum +                AND ( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 ) +          ) +"; } +  =back  =head1 SUBROUTINES | 
