From 3913f6d159b5b8110061690b7c97642c27abf7eb Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 10 Jun 2004 12:31:32 +0000 Subject: [PATCH] agent interface --- FS/FS/CGI.pm | 33 ++ FS/FS/ClientAPI/Agent.pm | 113 ++++++ FS/FS/ClientAPI/MyAccount.pm | 79 +++- FS/FS/ClientAPI/Signup.pm | 64 ++- FS/FS/agent.pm | 104 ++++- FS/FS/cust_main.pm | 130 ++++++ fs_selfservice/FS-SelfService/SelfService.pm | 446 ++++++++++++++++++++- fs_selfservice/FS-SelfService/cgi/agent.cgi | 256 ++++++++++++ fs_selfservice/FS-SelfService/cgi/agent_login.html | 22 + fs_selfservice/FS-SelfService/cgi/agent_main.html | 40 ++ fs_selfservice/FS-SelfService/cgi/cvv2.html | 25 ++ fs_selfservice/FS-SelfService/cgi/cvv2.png | Bin 0 -> 3854 bytes fs_selfservice/FS-SelfService/cgi/cvv2_amex.png | Bin 0 -> 4573 bytes .../FS-SelfService/cgi/list_customers.html | 41 ++ fs_selfservice/FS-SelfService/cgi/signup.html | 233 +++++++++++ .../FS-SelfService/cgi/view_customer.html | 84 ++++ fs_signup/FS-SignupClient/SignupClient.pm | 52 ++- fs_signup/FS-SignupClient/cgi/signup.cgi | 267 +----------- httemplate/browse/agent.cgi | 28 +- httemplate/search/cust_main.cgi | 111 ++--- 20 files changed, 1720 insertions(+), 408 deletions(-) create mode 100644 FS/FS/ClientAPI/Agent.pm create mode 100644 fs_selfservice/FS-SelfService/cgi/agent.cgi create mode 100644 fs_selfservice/FS-SelfService/cgi/agent_login.html create mode 100644 fs_selfservice/FS-SelfService/cgi/agent_main.html create mode 100644 fs_selfservice/FS-SelfService/cgi/cvv2.html create mode 100644 fs_selfservice/FS-SelfService/cgi/cvv2.png create mode 100644 fs_selfservice/FS-SelfService/cgi/cvv2_amex.png create mode 100644 fs_selfservice/FS-SelfService/cgi/list_customers.html create mode 100755 fs_selfservice/FS-SelfService/cgi/signup.html create mode 100644 fs_selfservice/FS-SelfService/cgi/view_customer.html 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 #'. $cust_main->custnum. ''. + ' - '. + ucfirst($cust_main->status). ''. ntable('#e8e8e8'). ''. ntable("#cccccc",2). 'Billing
Address'. $cust_main->getfield('last'). ', '. $cust_main->first. '
'; @@ -305,6 +307,20 @@ sub small_custview { $html .= $cust_main->country. '
' if $cust_main->country && $cust_main->country ne $countrydefault; + $html .= ''; + if ( $cust_main->daytime && $cust_main->night ) { + use FS::Msgcat; + $html .= ( FS::Msgcat::_gettext('daytime') || 'Day' ). + ' '. $cust_main->daytime. + '
'. ( 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 .= '
Fax '. $cust_main->fax; + } + $html .= ''; 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 .= ''; + + 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"). + '
'. ( 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 .= '
Fax '. $cust_main->get("${pre}fax"); + } + $html .= ''; } 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 diff --git a/fs_selfservice/FS-SelfService/SelfService.pm b/fs_selfservice/FS-SelfService/SelfService.pm index 920415e30..2cda9fe2d 100644 --- a/fs_selfservice/FS-SelfService/SelfService.pm +++ b/fs_selfservice/FS-SelfService/SelfService.pm @@ -18,24 +18,28 @@ $socket .= '.'.$tag if defined $tag && length($tag); #maybe should ask ClientAPI for this list %autoload = ( - 'passwd' => 'passwd/passwd', - 'chfn' => 'passwd/passwd', - 'chsh' => 'passwd/passwd', - 'login' => 'MyAccount/login', - 'customer_info' => 'MyAccount/customer_info', - 'edit_info' => 'MyAccount/edit_info', - 'invoice' => 'MyAccount/invoice', - 'cancel' => 'MyAccount/cancel', - 'payment_info' => 'MyAccount/payment_info', - 'process_payment' => 'MyAccount/process_payment', - 'list_pkgs' => 'MyAccount/list_pkgs', - 'order_pkg' => 'MyAccount/order_pkg', - 'cancel_pkg' => 'MyAccount/cancel_pkg', - 'charge' => 'MyAccount/charge', - 'signup_info' => 'Signup/signup_info', - 'new_customer' => 'Signup/new_customer', + 'passwd' => 'passwd/passwd', + 'chfn' => 'passwd/passwd', + 'chsh' => 'passwd/passwd', + 'login' => 'MyAccount/login', + 'customer_info' => 'MyAccount/customer_info', + 'edit_info' => 'MyAccount/edit_info', + 'invoice' => 'MyAccount/invoice', + 'list_invoices' => 'MyAccount/list_invoices', + 'cancel' => 'MyAccount/cancel', + 'payment_info' => 'MyAccount/payment_info', + 'process_payment' => 'MyAccount/process_payment', + 'list_pkgs' => 'MyAccount/list_pkgs', + 'order_pkg' => 'MyAccount/order_pkg', + 'cancel_pkg' => 'MyAccount/cancel_pkg', + 'charge' => 'MyAccount/charge', + 'signup_info' => 'Signup/signup_info', + 'new_customer' => 'Signup/new_customer', + 'agent_login' => 'Agent/agent_login', + 'agent_info' => 'Agent/agent_info', + 'agent_list_customers' => 'Agent/agent_list_customers', ); -@EXPORT_OK = keys %autoload; +@EXPORT_OK = ( keys(%autoload), qw( regionselector expselect popselector ) ); $ENV{'PATH'} ='/usr/bin:/usr/ucb:/bin'; $ENV{'SHELL'} = '/bin/sh'; @@ -286,6 +290,37 @@ Invoice text =back +=item list_invoices HASHREF + +Returns a list of all customer invoices. Takes a hash references with a single +key, session_id. + +Returns a hash reference with the following keys: + +=over 4 + +=item error + +Empty on success, or an error message on errors + +=item invoices + +Reference to array of hash references with the following keys: + +=over 4 + +=item invnum + +Invoice ID + +=item _date + +Invoice date, in UNIX epoch time + +=back + +=back + =item cancel HASHREF Cancels this customer. @@ -492,7 +527,15 @@ error message on errors. =over 4 -=item signup_info +=item signup_info HASHREF + +Takes a hash reference as parameter with the following keys: + +=over 4 + +=item session_id - Optional agent/reseller interface session + +=back Returns a hash reference containing information that may be useful in displaying a signup page. The hash reference contains the following keys: @@ -505,7 +548,9 @@ County/state/country data - array reference of hash references, each of which ha =item part_pkg -Available packages - array reference of hash references, each of which has the fields of a part_pkg record (see L). Each hash reference also has an additional 'payby' field containing an array reference of acceptable payment types specific to this package (see below and L). Note these are not FS::part_pkg objects, but hash references of columns and values. Requires the 'signup_server-default_agentnum' configuration value to be set. +Available packages - array reference of hash references, each of which has the fields of a part_pkg record (see L). Each hash reference also has an additional 'payby' field containing an array reference of acceptable payment types specific to this package (see below and L). Note these are not FS::part_pkg objects, but hash references of columns and values. Requires the 'signup_server-default_agentnum' configuration value to be set, or +an agentnum specified explicitly via reseller interface session_id in the +options. =item agent @@ -634,6 +679,369 @@ Returns a hash reference with the following keys: =back +=item regionselector HASHREF | LIST + +Takes as input a hashref or list of key/value pairs with the following keys: + +=over 4 + +=item selected_county + +=item selected_state + +=item selected_country + +=item prefix - Specify a unique prefix string if you intend to use the HTML output multiple time son one page. + +=item onchange - Specify a javascript subroutine to call on changes + +=item default_state + +=item default_country + +=item locales - An arrayref of hash references specifying regions. Normally you can just pass the value of the I field returned by B. + +=back + +Returns a list consisting of three HTML fragments for county selection, +state selection and country selection, respectively. + +=cut + +#false laziness w/FS::cust_main_county (this is currently the "newest" version) +sub regionselector { + my $param; + if ( ref($_[0]) ) { + $param = shift; + } else { + $param = { @_ }; + } + $param->{'selected_country'} ||= $param->{'default_country'}; + $param->{'selected_state'} ||= $param->{'default_state'}; + + my $prefix = exists($param->{'prefix'}) ? $param->{'prefix'} : ''; + + my $countyflag = 0; + + my %cust_main_county; + +# unless ( @cust_main_county ) { #cache + #@cust_main_county = qsearch('cust_main_county', {} ); + #foreach my $c ( @cust_main_county ) { + foreach my $c ( @{ $param->{'locales'} } ) { + #$countyflag=1 if $c->county; + $countyflag=1 if $c->{county}; + #push @{$cust_main_county{$c->country}{$c->state}}, $c->county; + #$cust_main_county{$c->country}{$c->state}{$c->county} = 1; + $cust_main_county{$c->{country}}{$c->{state}}{$c->{county}} = 1; + } +# } + $countyflag=1 if $param->{selected_county}; + + my $script_html = < + function opt(what,value,text) { + var optionName = new Option(text, value, false, false); + var length = what.length; + what.options[length] = optionName; + } + function ${prefix}country_changed(what) { + country = what.options[what.selectedIndex].text; + for ( var i = what.form.${prefix}state.length; i >= 0; i-- ) + what.form.${prefix}state.options[i] = null; +END + #what.form.${prefix}state.options[0] = new Option('', '', false, true); + + foreach my $country ( sort keys %cust_main_county ) { + $script_html .= "\nif ( country == \"$country\" ) {\n"; + foreach my $state ( sort keys %{$cust_main_county{$country}} ) { + my $text = $state || '(n/a)'; + $script_html .= qq!opt(what.form.${prefix}state, "$state", "$text");\n!; + } + $script_html .= "}\n"; + } + + $script_html .= <= 0; i-- ) + what.form.${prefix}county.options[i] = null; +END + + foreach my $country ( sort keys %cust_main_county ) { + $script_html .= "\nif ( country == \"$country\" ) {\n"; + foreach my $state ( sort keys %{$cust_main_county{$country}} ) { + $script_html .= "\nif ( state == \"$state\" ) {\n"; + #foreach my $county ( sort @{$cust_main_county{$country}{$state}} ) { + foreach my $county ( sort keys %{$cust_main_county{$country}{$state}} ) { + my $text = $county || '(n/a)'; + $script_html .= + qq!opt(what.form.${prefix}county, "$county", "$text");\n!; + } + $script_html .= "}\n"; + } + $script_html .= "}\n"; + } + } + + $script_html .= < +END + + my $county_html = $script_html; + if ( $countyflag ) { + $county_html .= qq!'; + } else { + $county_html .= + qq!!; + } + + my $state_html = qq!'; + + $state_html .= ''; + + my $country_html = qq!'; + + ($county_html, $state_html, $country_html); + +} + +#=item expselect HASHREF | LIST +# +#Takes as input a hashref or list of key/value pairs with the following keys: +# +#=over 4 +# +#=item prefix - Specify a unique prefix string if you intend to use the HTML output multiple time son one page. +# +#=item date - current date, in yyyy-mm-dd or m-d-yyyy format +# +#=back + +=item expselect PREFIX [ DATE ] + +Takes as input a unique prefix string and the current expiration date, in +yyyy-mm-dd or m-d-yyyy format + +Returns an HTML fragments for expiration date selection. + +=cut + +sub expselect { + #my $param; + #if ( ref($_[0]) ) { + # $param = shift; + #} else { + # $param = { @_ }; + #my $prefix = $param->{'prefix'}; + #my $prefix = exists($param->{'prefix'}) ? $param->{'prefix'} : ''; + #my $date = exists($param->{'date'}) ? $param->{'date'} : ''; + my $prefix = shift; + my $date = scalar(@_) ? shift : ''; + + my( $m, $y ) = ( 0, 0 ); + if ( $date =~ /^(\d{4})-(\d{2})-\d{2}$/ ) { #PostgreSQL date format + ( $m, $y ) = ( $2, $1 ); + } elsif ( $date =~ /^(\d{1,2})-(\d{1,2}-)?(\d{4}$)/ ) { + ( $m, $y ) = ( $1, $3 ); + } + my $return = qq!!; + my @t = localtime; + my $thisYear = $t[5] + 1900; + for ( ($thisYear > $y && $y > 0 ? $y : $thisYear) .. 2037 ) { + $return .= " field returned by B. + +=back + +Returns an HTML fragment for access number selection. + +=cut + +#horrible false laziness with FS/FS/svc_acct_pop.pm::popselector +sub popselector { + my $param; + if ( ref($_[0]) ) { + $param = shift; + } else { + $param = { @_ }; + } + my $popnum = $param->{'popnum'}; + my $pops = $param->{'pops'}; + + return '' unless @$pops; + return $pops->[0]{city}. ', '. $pops->[0]{state}. + ' ('. $pops->[0]{ac}. ')/'. $pops->[0]{exch}. '-'. $pops->[0]{loc}. + '' + if scalar(@$pops) == 1; + + my %pop = (); + my %popnum2pop = (); + foreach (@$pops) { + push @{ $pop{ $_->{state} }->{ $_->{ac} } }, $_; + $popnum2pop{$_->{popnum}} = $_; + } + + my $text = < + function opt(what,href,text) { + var optionName = new Option(text, href, false, false) + var length = what.length; + what.options[length] = optionName; + } +END + + my $init_popstate = $param->{'init_popstate'}; + if ( $init_popstate ) { + $text .= ''; + } else { + $text .= <{'popac'}) { + $text .= "what.form.popac.options[what.form.popac.length-1].selected = true;\n"; + } + } + $text .= "}\n" unless $init_popstate; + } + $text .= "popac_changed(what.form.popac)}\n"; + + $text .= <{$popac}}) { + my $o_popnum = $pop->{popnum}; + my $poptext = $pop->{city}. ', '. $pop->{state}. + ' ('. $pop->{ac}. ')/'. $pop->{exch}. '-'. $pop->{loc}; + + $text .= "opt(what.form.popnum, \"$o_popnum\", \"$poptext\");\n"; + if ($popnum == $o_popnum) { + $text .= "what.form.popnum.options[what.form.popnum.length-1].selected = true;\n"; + } + } + $text .= "}\n"; + } + } + + + $text .= "}\n\n"; + + $text .= + qq!'; + + $text .= + qq!!; + + $text .= qq!
'; #callback? return 3 html pieces? #'
!; + + $text; + +} + +=back + +=head1 RESELLER FUNCTIONS + +Note: Resellers can also use the B and B functions +with their active session. + +=over 4 + +=item agent_login + +=item agent_info + +=item agent_list_customers =back diff --git a/fs_selfservice/FS-SelfService/cgi/agent.cgi b/fs_selfservice/FS-SelfService/cgi/agent.cgi new file mode 100644 index 000000000..3508e82e3 --- /dev/null +++ b/fs_selfservice/FS-SelfService/cgi/agent.cgi @@ -0,0 +1,256 @@ +#!/usr/bin/perl -Tw + +#some false laziness w/selfservice.cgi + +use strict; +use vars qw($cgi $session_id $form_max $template_dir); +use subs qw(do_template); +use CGI; +use CGI::Carp qw(fatalsToBrowser); +use Business::CreditCard; +use Text::Template; +use FS::SelfService qw( agent_login agent_info + agent_list_customers + signup_info new_customer + customer_info order_pkg + ); + +$template_dir = '.'; + +$form_max = 255; + +$cgi = new CGI; + +unless ( defined $cgi->param('session') ) { + do_template('agent_login',{}); + exit; +} + +if ( $cgi->param('session') eq 'login' ) { + + $cgi->param('username') =~ /^\s*([a-z0-9_\-\.\&]{0,$form_max})\s*$/i + or die "illegal username"; + my $username = $1; + + $cgi->param('password') =~ /^(.{0,$form_max})$/ + or die "illegal password"; + my $password = $1; + + my $rv = agent_login( + 'username' => $username, + 'password' => $password, + ); + if ( $rv->{error} ) { + do_template('agent_login', { + 'error' => $rv->{error}, + 'username' => $username, + } ); + exit; + } else { + $cgi->param('session' => $rv->{session_id} ); + $cgi->param('action' => 'agent_main' ); + } +} + +$session_id = $cgi->param('session'); + +$cgi->param('action') =~ + /^(agent_main|signup|process_signup|list_customers|view_customer|process_order_pkg)$/ + or die "unknown action ". $cgi->param('action'); +my $action = $1; + +warn "running $action\n"; +my $result = eval "&$action();"; +die $@ if $@; + +if ( $result->{error} eq "Can't resume session" ) { #ick + do_template('agent_login',{}); + exit; +} + +warn "processing template $action\n"; +do_template($action, { + 'session_id' => $session_id, + %{$result} +}); + +#-- + +sub agent_main { agent_info( 'session_id' => $session_id ); } + +sub signup { signup_info( 'session_id' => $session_id ); } + +sub process_signup { + + my $init_data = signup_info( 'session_id' => $session_id ); + if ( $init_data->{'error'} ) { + if ( $init_data->{'error'} eq "Can't resume session" ) { #ick + do_template('agent_login',{}); + exit; + } else { #? + die $init_data->{'error'}; + } + } + + my $error = ''; + + #some false laziness w/signup.cgi + my $payby = $cgi->param('payby'); + if ( $payby eq 'CHEK' || $payby eq 'DCHK' ) { + #$payinfo = join('@', map { $cgi->param( $payby. "_payinfo$_" ) } (1,2) ); + $cgi->param('payinfo' => $cgi->param($payby. '_payinfo1'). '@'. + $cgi->param($payby. '_payinfo2') + ); + } else { + $cgi->param('payinfo' => $cgi->param( $payby. '_payinfo' ) ); + } + $cgi->param('paydate' => $cgi->param( $payby. '_month' ). '-'. + $cgi->param( $payby. '_year' ) + ); + $cgi->param('payname' => $cgi->param( $payby. '_payname' ) ); + $cgi->param('paycvv' => defined $cgi->param( $payby. '_paycvv' ) + ? $cgi->param( $payby. '_paycvv' ) + : '' + ); + + if ( $cgi->param('invoicing_list') ) { + $cgi->param('invoicing_list' => $cgi->param('invoicing_list'). ', POST') + if $cgi->param('invoicing_list_POST'); + } else { + $cgi->param('invoicing_list' => 'POST' ); + } + + if ( $cgi->param('_password') ne $cgi->param('_password2') ) { + $error = $init_data->{msgcat}{passwords_dont_match}; #msgcat + $cgi->param('_password', ''); + $cgi->param('_password2', ''); + } + + if ( $payby =~ /^(CARD|DCRD)$/ && $cgi->param('CARD_type') ) { + my $payinfo = $cgi->param('payinfo'); + $payinfo =~ s/\D//g; + + $payinfo =~ /^(\d{13,16})$/ + or $error ||= $init_data->{msgcat}{invalid_card}; #. $self->payinfo; + $payinfo = $1; + validate($payinfo) + or $error ||= $init_data->{msgcat}{invalid_card}; #. $self->payinfo; + cardtype($payinfo) eq $cgi->param('CARD_type') + or $error ||= $init_data->{msgcat}{not_a}. $cgi->param('CARD_type'); + } + + unless ( $error ) { + my $rv = new_customer ( { + 'session_id' => $session_id, + map { $_ => $cgi->param($_) } + qw( last first ss company + address1 address2 city county state zip country + daytime night fax + payby payinfo paycvv paydate payname invoicing_list + pkgpart username sec_phrase _password popnum refnum + ), + grep { /^snarf_/ } $cgi->param + } ); + $error = $rv->{'error'}; + } + + if ( $error ) { + $action = 'signup'; + my $r = { + $cgi->Vars, + %{$init_data}, + 'error' => $error, + }; + #warn join('\n', map "$_ => $r->{$_}", keys %$r )."\n"; + $r; + } else { + $action = 'agent_main'; + my $agent_info = agent_info( 'session_id' => $session_id ); + $agent_info->{'message'} = 'Signup sucessful'; + $agent_info; + } + +} + +sub list_customers { + agent_list_customers( 'session_id' => $session_id, + map { $_ => $cgi->param($_) } + grep defined($cgi->param($_)), + qw(prospect active susp cancel) + ); +} + +sub view_customer { + + my $init_data = signup_info( 'session_id' => $session_id ); + if ( $init_data->{'error'} ) { + if ( $init_data->{'error'} eq "Can't resume session" ) { #ick + do_template('agent_login',{}); + exit; + } else { #? + die $init_data->{'error'}; + } + } + + my $customer_info = customer_info ( + 'agent_session_id' => $session_id, + 'custnum' => $cgi->param('custnum') + ); + + + return { + ( map { $_ => $init_data->{$_} } + qw( part_pkg security_phrase svc_acct_pop ), + ), + %$customer_info, + }; +} + +sub process_order_pkg { + + my $results = order_pkg ( + 'agent_session_id' => $session_id, + map { $_ => $cgi->param($_) } + qw( custnum pkgpart username _password _password2 sec_phrase popnum ) + ); + + $action = 'view_customer'; + $cgi->delete( grep { $_ ne 'custnum' } $cgi->param ) + unless $results->{'error'}; + + return { + $cgi->Vars, + %{view_customer()}, + 'message' => $results->{'error'} + ? ''. $results->{'error'}. '' + : 'Package order sucessful.' + }; + +} + +#-- + +sub do_template { + my $name = shift; + my $fill_in = shift; + #warn join(' / ', map { "$_=>".$fill_in->{$_} } keys %$fill_in). "\n"; + + $cgi->delete_all(); + $fill_in->{'selfurl'} = $cgi->self_url; + $fill_in->{'cgi'} = \$cgi; + + my $template = new Text::Template( TYPE => 'FILE', + SOURCE => "$template_dir/$name.html", + DELIMITERS => [ '<%=', '%>' ], + UNTAINT => 1, ) + or die $Text::Template::ERROR; + + print $cgi->header( '-expires' => 'now' ), + $template->fill_in( PACKAGE => 'FS::SelfService::_agentcgi', + HASH => $fill_in + ); +} + +package FS::SelfService::_agentcgi; +use FS::SelfService qw(regionselector expselect popselector); + diff --git a/fs_selfservice/FS-SelfService/cgi/agent_login.html b/fs_selfservice/FS-SelfService/cgi/agent_login.html new file mode 100644 index 000000000..4b0778ec5 --- /dev/null +++ b/fs_selfservice/FS-SelfService/cgi/agent_login.html @@ -0,0 +1,22 @@ +Reseller Login +Reseller Login

+<%= $error %> +
+ + + + + + + + + + +
Username + +
Password + +
+

+
+ diff --git a/fs_selfservice/FS-SelfService/cgi/agent_main.html b/fs_selfservice/FS-SelfService/cgi/agent_main.html new file mode 100644 index 000000000..89a1b330d --- /dev/null +++ b/fs_selfservice/FS-SelfService/cgi/agent_main.html @@ -0,0 +1,40 @@ +Reseller Main +Reseller Main

+<%= $url = "$selfurl?session=$session_id;action="; ''; %> +
+Reseller Main
+ +
+ +<%= $message + ? "$message" + : "Hello $agent!" +%>

+ + + +
Customer summary
+ + <%= $num_prospect %> + prospects + +
<%= $num_active %> + active + +
<%= $num_susp %> + suspended + +
<%= $num_cancel %> + cancelled + +
+ +
New customer + +
+
+powered by freeside + + + + diff --git a/fs_selfservice/FS-SelfService/cgi/cvv2.html b/fs_selfservice/FS-SelfService/cgi/cvv2.html new file mode 100644 index 000000000..b178c8513 --- /dev/null +++ b/fs_selfservice/FS-SelfService/cgi/cvv2.html @@ -0,0 +1,25 @@ + + + + CVV2 information + + + + The CVV2 number (also called CVC2 or CID) is a three- or four-digit + security code used to reduce credit card fraud.

+ + + + + + + + +
Visa / MasterCard / DiscoverAmerican Express
+ Visa/MasterCard/Discover + + American Express +
+
(close window)
+ + diff --git a/fs_selfservice/FS-SelfService/cgi/cvv2.png b/fs_selfservice/FS-SelfService/cgi/cvv2.png new file mode 100644 index 0000000000000000000000000000000000000000..4610dcbe62aa30a493a84265090f59ade25d83f8 GIT binary patch literal 3854 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 literal 0 HcmV?d00001 diff --git a/fs_selfservice/FS-SelfService/cgi/cvv2_amex.png b/fs_selfservice/FS-SelfService/cgi/cvv2_amex.png new file mode 100644 index 0000000000000000000000000000000000000000..21c36a0ab5eb9f9fe56bb994007ac2d5284d55c5 GIT binary patch literal 4573 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 Hu0mjf_HDMR literal 0 HcmV?d00001 diff --git a/fs_selfservice/FS-SelfService/cgi/list_customers.html b/fs_selfservice/FS-SelfService/cgi/list_customers.html new file mode 100644 index 000000000..6d4ba564e --- /dev/null +++ b/fs_selfservice/FS-SelfService/cgi/list_customers.html @@ -0,0 +1,41 @@ +Reseller Main +Reseller Main

+<%= $url = "$selfurl?session=$session_id;action="; ''; %> +
+Reseller Main
+ +
+ +<%= + if ( @customers ) { + $OUT .= ''. + ''. + "$td{'statuscolor'}. '">'. + ucfirst($customer->{'status'}). "". "$td". + "$td$a". $customer->{'name'}. "". + ''; + #"$td". + $col = $col eq $col1 ? $col2 : $col1; + } + $OUT .= '
Customers'; + my $col1 = "ffffff"; + my $col2 = "dddddd"; + my $col = $col1; + + foreach my $customer ( @customers ) { + my $td = qq!!; + my $a = qq!'; + $OUT .= + '
'; + } else { + $OUT .= 'No customers.

'; + } +%> + +
+
+powered by freeside + + + diff --git a/fs_selfservice/FS-SelfService/cgi/signup.html b/fs_selfservice/FS-SelfService/cgi/signup.html new file mode 100755 index 000000000..973035179 --- /dev/null +++ b/fs_selfservice/FS-SelfService/cgi/signup.html @@ -0,0 +1,233 @@ +<%= $agent || 'ISP' %> Signup form + + +<%= $agent || 'ISP' %> Signup form

+<%= $error %> +
+ + + + +Where did you hear about our service?

+Contact Information + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
*Contact name
(last, first)
, +
Company
*Address
 
*City*State/Country + <%= + ($county_html, $state_html, $country_html) = + regionselector( { + selected_county => $county, + selected_state => $state, + selected_country => $country, + default_state => $statedefault, + default_country => $countrydefault, + locales => \@cust_main_county, + } ); + + "$county_html $state_html"; + %> + *Zip
*Country<%= $country_html %>
Day Phone
Night Phone
Fax
* required fields
+
Billing information + + +<%= scalar(@payby) > 1 ? '' : '' %> +
+ + <%= + $OUT .= ' + + Postal mail invoice +
Email invoice +
Billing type
+ + + + <%= + + my $cardselect = ''; + + my %payby = ( + 'CARD' => qq!Credit card
*$cardselect
*Exp !. expselect("CARD"). qq!
*Name on card
!, + 'DCRD' => qq!Credit card
*$cardselect
*Exp !. expselect("DCRD"). qq!
*Name on card
!, + 'CHEK' => qq!Electronic check
${r}Account number
${r}ABA/Routing code
${r}Bank name !, + 'DCHK' => qq!Electronic check
${r}Account number
${r}ABA/Routing code
${r}Bank name !, + 'LECB' => qq!Phone bill billing
${r}Phone number !, + 'BILL' => qq!Billing
P.O.
*Exp !. expselect("BILL", "12-2037"). qq!
*Attention
!, + 'COMP' => qq!Complimentary
*Approved by
*Exp !. expselect("COMP"), + 'PREPAY' => qq!Prepaid card
*!, + ); + + if ( $cvv_enabled ) { + foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5 + $payby{$payby} .= qq!
CVV2 (help!; + } + } + + my( $account, $aba ) = split('@', $payinfo); + my %paybychecked = ( + 'CARD' => qq!Credit card
*$cardselect
*Exp !. expselect("CARD", $paydate). qq!
*Name on card
!, + 'DCRD' => qq!Credit card
*$cardselect
*Exp !. expselect("DCRD", $paydate). qq!
*Name on card
!, + 'CHEK' => qq!Electronic check
${r}Account number
${r}ABA/Routing code
${r}Bank name !, + 'DCHK' => qq!Electronic check
${r}Account number
${r}ABA/Routing code
${r}Bank name !, + 'LECB' => qq!Phone bill billing
${r}Phone number !, + 'BILL' => qq!Billing
P.O.
*Exp !. expselect("BILL", $paydate). qq!
*Attention
!, + 'COMP' => qq!Complimentary
*Approved by
*Exp !. expselect("COMP", $paydate), + 'PREPAY' => qq!Prepaid card
*!, + ); + + if ( $cvv_enabled ) { + foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5 + $paybychecked{$payby} .= qq!
CVV2 (help!; + } + } + + for (@payby) { + if ( scalar(@payby) == 1) { + $OUT .= '"; + } else { + $OUT .= qq!!; + } else { + $OUT .= qq!> $payby{$_}!; + } + + } + } + %> + +
'. + qq!!. + "$paybychecked{$_} $paybychecked{$_}
* required fields for each billing type +

First package + + + + + + + + + + + + + + + + +<%= + if ( $security_phrase ) { + $OUT .= < + + + +ENDOUT + } else { + $OUT .= ''; + } +%> +<%= + if ( @svc_acct_pop ) { + $OUT .= ''; + } else { + $OUT .= popselector(popnum=>$popnum, pops=>\@svc_acct_pop); + } +%> +
Username
Password
Re-enter Password
Security Phrase +
Access number'. + popselector( 'popnum' => $popnum, + 'pops' => \@svc_acct_pop, + 'init_popstate' => $init_popstate, + 'popac' => $popac, + 'acstate' => $acstate, + ). + '
+

+
diff --git a/fs_selfservice/FS-SelfService/cgi/view_customer.html b/fs_selfservice/FS-SelfService/cgi/view_customer.html new file mode 100644 index 000000000..e4e9be250 --- /dev/null +++ b/fs_selfservice/FS-SelfService/cgi/view_customer.html @@ -0,0 +1,84 @@ +View Customer +View Customer

+<%= $url = "$selfurl?session=$session_id;action="; ''; %> +
+Reseller Main
+ +
+ +<%= $message + ? "$message

" + : '' +%> + +<%= $small_custview %> + +
Purchase additional package +
+ + + + + + + + + + + + + + + + + + + +<%= + if ( $security_phrase ) { + $OUT .= < + + + +ENDOUT + } else { + $OUT .= ''; + } +%> +<%= + if ( @svc_acct_pop ) { + $OUT .= ''; + } else { + $OUT .= popselector(popnum=>$popnum, pops=>\@svc_acct_pop); + } +%> +
Username
Password
Re-enter Password
Security Phrase +
Access number'. + popselector( 'popnum' => $popnum, + 'pops' => \@svc_acct_pop, + 'init_popstate' => $init_popstate, + 'popac' => $popac, + 'acstate' => $acstate, + ). + '
+ +
+ +
+
+powered by freeside + + + + diff --git a/fs_signup/FS-SignupClient/SignupClient.pm b/fs_signup/FS-SignupClient/SignupClient.pm index fb2b12fb0..b646baca2 100644 --- a/fs_signup/FS-SignupClient/SignupClient.pm +++ b/fs_signup/FS-SignupClient/SignupClient.pm @@ -1,7 +1,7 @@ package FS::SignupClient; use strict; -use vars qw($VERSION @ISA @EXPORT_OK); # $fs_signupd_socket); +use vars qw($VERSION @ISA @EXPORT_OK $init_data); # $fs_signupd_socket); use Exporter; #use Socket; #use FileHandle; @@ -12,7 +12,7 @@ use FS::SelfService; # qw( new_customer signup_info ); $VERSION = '0.04'; @ISA = qw( Exporter ); -@EXPORT_OK = qw( signup_info new_customer ); +@EXPORT_OK = qw( signup_info new_customer regionselector ); =head1 NAME @@ -99,7 +99,7 @@ Each hash reference has the following keys: #compatibility bit sub signup_info { - my $init_data = FS::SelfService::signup_info(); + $init_data = FS::SelfService::signup_info(); (map { $init_data->{$_} } qw( cust_main_county part_pkg svc_acct_pop ) ), $init_data; @@ -148,10 +148,56 @@ sub new_customer { $hash->{'error'}; } +=item regionselector SELECTED_COUNTY, SELECTED_STATE, SELECTED_COUNTRY, PREFIX, ONCHANGE + +=cut + +sub regionselector { + my ( $selected_county, $selected_state, $selected_country, + $prefix, $onchange ) = @_; + signup_info() unless $init_data; + FS::SelfService::regionselector({ + selected_county => $selected_county, + selected_state => $selected_state, + selected_country => $selected_country, + prefix => $prefix, + onchange => $onchange, + default_country => $init_data->{countrydefault}, + locales => $init_data->{cust_main_county}, + }); + #default_state => $init_data->{statedefault}, +} + +=item expselect PREFIX, DATE + +=cut + +sub expselect { + FS::SelfService::expselect(@_); +} + +=item popselector + +=cut + +sub popselector { + my( $popnum ) = @_; + signup_info() unless $init_data; + FS::SelfService::popselector({ + popnum => $popnum, + pops => $init_data->{svc_acct_pop}, + }); + #popac => + #acstate => +} + =back =head1 BUGS +This is just a wrapper around FS::SelfService functions for backwards +compatibility and will probably be deprecated soon. + =head1 SEE ALSO L, L diff --git a/fs_signup/FS-SignupClient/cgi/signup.cgi b/fs_signup/FS-SignupClient/cgi/signup.cgi index 0a9a51008..00a7aa61e 100755 --- a/fs_signup/FS-SignupClient/cgi/signup.cgi +++ b/fs_signup/FS-SignupClient/cgi/signup.cgi @@ -1,6 +1,6 @@ #!/usr/bin/perl -Tw # -# $Id: signup.cgi,v 1.50 2004-01-04 03:52:54 ivan Exp $ +# $Id: signup.cgi,v 1.51 2004-06-10 12:31:32 ivan Exp $ use strict; use vars qw( @payby $cgi $locales $packages @@ -20,14 +20,14 @@ use vars qw( @payby $cgi $locales $packages $self_url ); use subs qw( print_form print_okay print_decline - success_default decline_default - expselect ); + success_default decline_default ); use CGI; #use CGI::Carp qw(fatalsToBrowser); use Text::Template; use Business::CreditCard; use HTTP::BrowserDetect; -use FS::SignupClient 0.03 qw( signup_info new_customer ); +use FS::SignupClient 0.03 qw( signup_info new_customer + regionselector expselect popselector); #acceptable payment methods # @@ -360,265 +360,6 @@ sub print_okay { } } -#horrible false laziness with FS/FS/svc_acct_pop.pm::popselector -sub popselector { - - my( $popnum ) = @_; - - return '' unless @$pops; - return $pops->[0]{city}. ', '. $pops->[0]{state}. - ' ('. $pops->[0]{ac}. ')/'. $pops->[0]{exch}. '-'. $pops->[0]{loc}. - '' - if scalar(@$pops) == 1; - - #my %pop = (); - #my %popnum2pop = (); - #foreach (@$pops) { - # push @{ $pop{ $_->{state} }->{ $_->{ac} } }, $_; - # $popnum2pop{$_->{popnum}} = $_; - #} - - my $text = < - function opt(what,href,text) { - var optionName = new Option(text, href, false, false) - var length = what.length; - what.options[length] = optionName; - } -END - - if ( $init_popstate ) { - $text .= ''; - } else { - $text .= <param('popac')) { - $text .= "what.form.popac.options[what.form.popac.length-1].selected = true;\n"; - } - } - $text .= "}\n" unless $init_popstate; - } - $text .= "popac_changed(what.form.popac)}\n"; - - $text .= <{$popac}}) { - my $o_popnum = $pop->{popnum}; - my $poptext = $pop->{city}. ', '. $pop->{state}. - ' ('. $pop->{ac}. ')/'. $pop->{exch}. '-'. $pop->{loc}; - - $text .= "opt(what.form.popnum, \"$o_popnum\", \"$poptext\");\n"; - if ($popnum == $o_popnum) { - $text .= "what.form.popnum.options[what.form.popnum.length-1].selected = true;\n"; - } - } - $text .= "}\n"; - } - } - - - $text .= "}\n\n"; - - $text .= - qq!'; - - $text .= - qq!!; - - $text .= qq!
'; #callback? return 3 html pieces? #'
!; - - $text; - -} - -sub expselect { - my $prefix = shift; - my $date = shift || ''; - my( $m, $y ) = ( 0, 0 ); - if ( $date =~ /^(\d{4})-(\d{2})-\d{2}$/ ) { #PostgreSQL date format - ( $m, $y ) = ( $2, $1 ); - } elsif ( $date =~ /^(\d{1,2})-(\d{1,2}-)?(\d{4}$)/ ) { - ( $m, $y ) = ( $1, $3 ); - } - my $return = qq!!; - for ( 2001 .. 2037 ) { - $return .= "county; - $countyflag=1 if $c->{county}; - #push @{$cust_main_county{$c->country}{$c->state}}, $c->county; - #$cust_main_county{$c->country}{$c->state}{$c->county} = 1; - $cust_main_county{$c->{country}}{$c->{state}}{$c->{county}} = 1; - } -# } - $countyflag=1 if $selected_county; - - my $script_html = < - function opt(what,value,text) { - var optionName = new Option(text, value, false, false); - var length = what.length; - what.options[length] = optionName; - } - function ${prefix}country_changed(what) { - country = what.options[what.selectedIndex].text; - for ( var i = what.form.${prefix}state.length; i >= 0; i-- ) - what.form.${prefix}state.options[i] = null; -END - #what.form.${prefix}state.options[0] = new Option('', '', false, true); - - foreach my $country ( sort keys %cust_main_county ) { - $script_html .= "\nif ( country == \"$country\" ) {\n"; - foreach my $state ( sort keys %{$cust_main_county{$country}} ) { - my $text = $state || '(n/a)'; - $script_html .= qq!opt(what.form.${prefix}state, "$state", "$text");\n!; - } - $script_html .= "}\n"; - } - - $script_html .= <= 0; i-- ) - what.form.${prefix}county.options[i] = null; -END - - foreach my $country ( sort keys %cust_main_county ) { - $script_html .= "\nif ( country == \"$country\" ) {\n"; - foreach my $state ( sort keys %{$cust_main_county{$country}} ) { - $script_html .= "\nif ( state == \"$state\" ) {\n"; - #foreach my $county ( sort @{$cust_main_county{$country}{$state}} ) { - foreach my $county ( sort keys %{$cust_main_county{$country}{$state}} ) { - my $text = $county || '(n/a)'; - $script_html .= - qq!opt(what.form.${prefix}county, "$county", "$text");\n!; - } - $script_html .= "}\n"; - } - $script_html .= "}\n"; - } - } - - $script_html .= < -END - - my $county_html = $script_html; - if ( $countyflag ) { - $county_html .= qq!'; - } else { - $county_html .= - qq!!; - } - - my $state_html = qq!'; - - $state_html .= ''; - - my $country_html = qq!'; - - ($county_html, $state_html, $country_html); - -} - sub success_default { #html to use if you don't specify a success file <<'END'; Signup successful diff --git a/httemplate/browse/agent.cgi b/httemplate/browse/agent.cgi index 2eef5bb91..af3288720 100755 --- a/httemplate/browse/agent.cgi +++ b/httemplate/browse/agent.cgi @@ -95,10 +95,30 @@ foreach my $agent ( sort { <%= $agent->agent %> <%= $agent->agent_type->atype %> - <%= $num_ncancelled %> - active -
<%= $num_cancelled %> - cancelled + + + <%= my $num_prospect = $agent->num_prospect_cust_main %> + + <% if ( $num_prospect ) { %> + <% } %>prospects<% if ($num_prospect ) { %><% } %> + +
+ <%= my $num_active = $agent->num_active_cust_main %> + + <% if ( $num_active ) { %> + <% } %>active<% if ( $num_active ) { %><% } %> + +
+ <%= my $num_susp = $agent->num_susp_cust_main %> + + <% if ( $num_susp ) { %> + <% } %>suspended<% if ( $num_susp ) { %><% } %> + +
+ <%= my $num_cancel = $agent->num_cancel_cust_main %> + + <% if ( $num_cancel ) { %> + <% } %>cancelled<% if ( $num_cancel ) { %><% } %> <%= $agent->freq %> <%= $agent->prog %> diff --git a/httemplate/search/cust_main.cgi b/httemplate/search/cust_main.cgi index 69a78d6fe..632d68df9 100755 --- a/httemplate/search/cust_main.cgi +++ b/httemplate/search/cust_main.cgi @@ -82,119 +82,62 @@ if ( $cgi->param('browse') } } - my $ncancelled = ''; + my @qual = (); - if ( driver_name eq 'mysql' ) { - - my $sql = "CREATE TEMPORARY TABLE temp1_$$ TYPE=MYISAM - SELECT cust_pkg.custnum,COUNT(*) as count - FROM cust_pkg,cust_main - WHERE cust_pkg.custnum = cust_main.custnum - AND ( cust_pkg.cancel IS NULL - OR cust_pkg.cancel = 0 ) - GROUP BY cust_pkg.custnum"; - my $sth = dbh->prepare($sql) or die dbh->errstr. " preparing $sql"; - $sth->execute or die "Error executing \"$sql\": ". $sth->errstr; - $sql = "CREATE TEMPORARY TABLE temp2_$$ TYPE=MYISAM - SELECT cust_pkg.custnum,COUNT(*) as count - FROM cust_pkg,cust_main - WHERE cust_pkg.custnum = cust_main.custnum - GROUP BY cust_pkg.custnum"; - $sth = dbh->prepare($sql) or die dbh->errstr. " preparing $sql"; - $sth->execute or die "Error executing \"$sql\": ". $sth->errstr; - } + my $ncancelled = ''; if ( $cgi->param('showcancelledcustomers') eq '0' #see if it was set by me || ( $conf->exists('hidecancelledcustomers') && ! $cgi->param('showcancelledcustomers') ) ) { #grep { $_->ncancelled_pkgs || ! $_->all_pkgs } - if ( driver_name eq 'mysql' ) { - $ncancelled = " - temp1_$$.custnum = cust_main.custnum - AND temp2_$$.custnum = cust_main.custnum - AND (temp1_$$.count > 0 - OR temp2_$$.count = 0 ) - "; - - } else { - $ncancelled = " - 0 < ( SELECT COUNT(*) FROM cust_pkg - WHERE cust_pkg.custnum = cust_main.custnum - AND ( cust_pkg.cancel IS NULL - OR cust_pkg.cancel = 0 - ) - ) - OR 0 = ( SELECT COUNT(*) FROM cust_pkg - WHERE cust_pkg.custnum = cust_main.custnum - ) - "; - } - } - - my $cancelled = ''; - if ( $cgi->param('cancelled') ) { - $cancelled = " - 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 + push @qual, " + ( 0 < ( SELECT COUNT(*) FROM cust_pkg + WHERE cust_pkg.custnum = cust_main.custnum + AND ( cust_pkg.cancel IS NULL + OR cust_pkg.cancel = 0 + ) + ) + OR 0 = ( SELECT COUNT(*) FROM cust_pkg WHERE cust_pkg.custnum = cust_main.custnum ) + ) "; - } + } + + push @qual, FS::cust_main->cancel_sql if $cgi->param('cancelled'); + push @qual, FS::cust_main->prospect_sql if $cgi->param('prospect'); + push @qual, FS::cust_main->active_sql if $cgi->param('active'); + push @qual, FS::cust_main->susp_sql if $cgi->param('suspended'); #EWWWWWW my $qual = join(' AND ', map { "$_ = ". dbh->quote($search{$_}) } keys %search ); - if ( $cancelled ) { - $qual .= ' AND ' if $qual; - $qual .= $cancelled; - } elsif ( $ncancelled ) { + my $addl_qual = join(' AND ', @qual); + + if ( $addl_qual ) { $qual .= ' AND ' if $qual; - $qual .= $ncancelled; + $qual .= $addl_qual; } $qual = " WHERE $qual" if $qual; - my $statement; - if ( driver_name eq 'mysql' ) { - $statement = "SELECT COUNT(*) FROM cust_main"; - $statement .= ", temp1_$$, temp2_$$ $qual" if $qual; - } else { - $statement = "SELECT COUNT(*) FROM cust_main $qual"; - } + my $statement = "SELECT COUNT(*) FROM cust_main $qual"; my $sth = dbh->prepare($statement) or die dbh->errstr." preparing $statement"; $sth->execute or die "Error executing \"$statement\": ". $sth->errstr; $total = $sth->fetchrow_arrayref->[0]; - my $rqual = $cancelled || $ncancelled; - if ( $rqual ) { + if ( $addl_qual ) { if ( %search ) { - $rqual = " AND $rqual"; + $addl_qual = " AND $addl_qual"; } else { - $rqual = " WHERE $rqual"; + $addl_qual = " WHERE $addl_qual"; } } - my @just_cust_main; - if ( driver_name eq 'mysql' ) { - @just_cust_main = qsearch('cust_main', \%search, 'cust_main.*', - ",temp1_$$,temp2_$$ $rqual $orderby $limit"); - } else { - @just_cust_main = qsearch('cust_main', \%search, '', - "$rqual $orderby $limit" ); - } - if ( driver_name eq 'mysql' ) { - my $sql = "DROP TABLE temp1_$$,temp2_$$;"; - my $sth = dbh->prepare($sql) or die dbh->errstr. " preparing $sql"; - $sth->execute or die "Error executing \"$sql\": ". $sth->errstr; - } - @cust_main = @just_cust_main; + @cust_main = qsearch('cust_main', \%search, '', + "$addl_qual $orderby $limit" ); # foreach my $cust_main ( @just_cust_main ) { # -- 2.11.0