diff options
author | ivan <ivan> | 2004-06-10 12:31:32 +0000 |
---|---|---|
committer | ivan <ivan> | 2004-06-10 12:31:32 +0000 |
commit | 3913f6d159b5b8110061690b7c97642c27abf7eb (patch) | |
tree | a5bc48080901dfe6c19c864c2c2f374990a2cfdd /FS | |
parent | e0c62c388f74e543328f3691e8a8a1edb451a804 (diff) |
agent interface
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 |