summaryrefslogtreecommitdiff
path: root/FS
diff options
context:
space:
mode:
authorivan <ivan>2004-06-10 12:31:32 +0000
committerivan <ivan>2004-06-10 12:31:32 +0000
commit3913f6d159b5b8110061690b7c97642c27abf7eb (patch)
treea5bc48080901dfe6c19c864c2c2f374990a2cfdd /FS
parente0c62c388f74e543328f3691e8a8a1edb451a804 (diff)
agent interface
Diffstat (limited to 'FS')
-rw-r--r--FS/FS/CGI.pm33
-rw-r--r--FS/FS/ClientAPI/Agent.pm113
-rw-r--r--FS/FS/ClientAPI/MyAccount.pm79
-rw-r--r--FS/FS/ClientAPI/Signup.pm64
-rw-r--r--FS/FS/agent.pm104
-rw-r--r--FS/FS/cust_main.pm130
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