summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FS/FS/ClientAPI/MyAccount.pm138
-rw-r--r--FS/FS/ClientAPI/Signup.pm2
-rw-r--r--FS/FS/cust_pkg.pm50
-rw-r--r--fs_selfservice/FS-SelfService/SelfService.pm42
-rw-r--r--fs_selfservice/FS-SelfService/cgi/agent.cgi4
-rw-r--r--fs_selfservice/FS-SelfService/cgi/delete_svc.html18
-rw-r--r--fs_selfservice/FS-SelfService/cgi/logout.html5
-rw-r--r--fs_selfservice/FS-SelfService/cgi/make_payment.html7
-rw-r--r--fs_selfservice/FS-SelfService/cgi/myaccount.html9
-rw-r--r--fs_selfservice/FS-SelfService/cgi/myaccount_menu.html13
-rw-r--r--fs_selfservice/FS-SelfService/cgi/payment_results.html7
-rw-r--r--fs_selfservice/FS-SelfService/cgi/process_svc_acct.html14
-rw-r--r--fs_selfservice/FS-SelfService/cgi/provision.html77
-rw-r--r--fs_selfservice/FS-SelfService/cgi/provision_svc_acct.html66
-rw-r--r--fs_selfservice/FS-SelfService/cgi/selfservice.cgi92
-rw-r--r--fs_selfservice/FS-SelfService/cgi/view_invoice.html9
-rwxr-xr-xhttemplate/view/cust_main.cgi40
17 files changed, 527 insertions, 66 deletions
diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm
index f51174e..639cb7b 100644
--- a/FS/FS/ClientAPI/MyAccount.pm
+++ b/FS/FS/ClientAPI/MyAccount.pm
@@ -22,6 +22,7 @@ use FS::cust_pkg;
use FS::ClientAPI; #hmm
FS::ClientAPI->register_handlers(
'MyAccount/login' => \&login,
+ 'MyAccount/logout' => \&logout,
'MyAccount/customer_info' => \&customer_info,
'MyAccount/edit_info' => \&edit_info,
'MyAccount/invoice' => \&invoice,
@@ -33,6 +34,9 @@ FS::ClientAPI->register_handlers(
'MyAccount/order_pkg' => \&order_pkg,
'MyAccount/cancel_pkg' => \&cancel_pkg,
'MyAccount/charge' => \&charge,
+ 'MyAccount/part_svc_info' => \&part_svc_info,
+ 'MyAccount/provision_acct' => \&provision_acct,
+ 'MyAccount/unprovision_svc' => \&unprovision_svc,
);
use vars qw( @cust_main_editable_fields );
@@ -92,6 +96,16 @@ sub login {
};
}
+sub logout {
+ my $p = shift;
+ if ( $p->{'session_id'} ) {
+ $cache->remove($p->{'session_id'});
+ return { 'error' => '' };
+ } else {
+ return { 'error' => "Can't resume session" }; #better error message
+ }
+}
+
sub customer_info {
my $p = shift;
@@ -445,7 +459,24 @@ sub list_pkgs {
my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
or return { 'error' => "unknown custnum $custnum" };
- return { 'cust_pkg' => [ map { $_->hashref } $cust_main->ncancelled_pkgs ] };
+ #return { 'cust_pkg' => [ map { $_->hashref } $cust_main->ncancelled_pkgs ] };
+
+ { 'svcnum' => $session->{'svcnum'},
+ 'cust_pkg' => [ map {
+ { $_->hash,
+ $_->part_pkg->hash,
+ part_svc =>
+ [ map $_->hashref, $_->available_part_svc ],
+ cust_svc =>
+ [ map { { $_->hash,
+ label => [ $_->label ],
+ }
+ } $_->cust_svc
+ ],
+ };
+ } $cust_main->ncancelled_pkgs
+ ],
+ };
}
@@ -598,5 +629,110 @@ sub cancel_pkg {
}
+sub provision_acct {
+ 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 $pkgnum = $p->{'pkgnum'};
+
+ my $cust_pkg = qsearchs('cust_pkg', { 'custnum' => $custnum,
+ 'pkgnum' => $pkgnum,
+ } )
+ or return { 'error' => "unknown pkgnum $pkgnum" };
+
+ my $part_svc = qsearchs('part_svc', { 'svcpart' => $p->{'svcpart'} } )
+ or return { 'error' => "unknown svcpart $p->{'svcpart'}" };
+
+ return { 'error' => gettext('passwords_dont_match') }
+ if $p->{'_password'} ne $p->{'_password2'};
+ return { 'error' => gettext('empty_password') }
+ unless length($p->{'_password'});
+
+ my $svc_acct = new FS::svc_acct( {
+ 'pkgnum' => $p->{'pkgnum'},
+ 'svcpart' => $p->{'svcpart'},
+ 'username' => $p->{'username'},
+ '_password' => $p->{'_password'},
+ } );
+
+ return { 'svc' => $part_svc->svc,
+ 'error' => $svc_acct->insert
+ };
+
+}
+
+sub part_svc_info {
+ 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 $pkgnum = $p->{'pkgnum'};
+
+ my $cust_pkg = qsearchs('cust_pkg', { 'custnum' => $custnum,
+ 'pkgnum' => $pkgnum,
+ } )
+ or return { 'error' => "unknown pkgnum $pkgnum" };
+
+ my $svcpart = $p->{'svcpart'};
+
+ my $pkg_svc = qsearchs('pkg_svc', { 'pkgpart' => $cust_pkg->pkgpart,
+ 'svcpart' => $svcpart, } )
+ or return { 'error' => "unknown svcpart $svcpart for pkgnum $pkgnum" };
+ my $part_svc = $pkg_svc->part_svc;
+
+ return {
+ 'svc' => $part_svc->svc,
+ 'svcdb' => $part_svc->svcdb,
+ 'pkgnum' => $pkgnum,
+ 'svcpart' => $svcpart,
+
+ 'security_phrase' => 0, #XXX !
+ 'svc_acct_pop' => [], #XXX !
+ 'popnum' => '',
+ 'init_popstate' => '',
+ 'popac' => '',
+ 'acstate' => '',
+ };
+
+}
+
+sub unprovision_svc {
+ 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 $svcnum = $p->{'svcnum'};
+
+ my $cust_svc = qsearchs('cust_svc', { 'svcnum' => $svcnum, } )
+ or return { 'error' => "unknown svcnum $svcnum" };
+
+ return { 'error' => "Service $svcnum does not belong to customer $custnum" }
+ unless $cust_svc->cust_pkg->custnum == $custnum;
+
+ return { 'svc' => $cust_svc->part_svc->svc,
+ 'error' => $cust_svc->cancel
+ };
+
+}
+
1;
diff --git a/FS/FS/ClientAPI/Signup.pm b/FS/FS/ClientAPI/Signup.pm
index 2e2b80f..81ed5e6 100644
--- a/FS/FS/ClientAPI/Signup.pm
+++ b/FS/FS/ClientAPI/Signup.pm
@@ -128,7 +128,7 @@ sub new_customer {
#return "Passwords don't match"
# if $hashref->{'_password'} ne $hashref->{'_password2'}
return { 'error' => gettext('empty_password') }
- unless $packet->{'_password'};
+ unless length($packet->{'_password'});
# a bit inefficient for large numbers of pops
return { 'error' => gettext('no_access_number_selected') }
unless $packet->{'popnum'} || !scalar(qsearch('svc_acct_pop',{} ));
diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm
index fb41dfc..d2a48e9 100644
--- a/FS/FS/cust_pkg.pm
+++ b/FS/FS/cust_pkg.pm
@@ -502,15 +502,22 @@ sub part_pkg {
: qsearchs( 'part_pkg', { 'pkgpart' => $self->pkgpart } );
}
-=item cust_svc
+=item cust_svc [ SVCPART ]
Returns the services for this package, as FS::cust_svc objects (see
-L<FS::cust_svc>)
+L<FS::cust_svc>). If a svcpart is specified, return only the matching
+services.
=cut
sub cust_svc {
my $self = shift;
+
+ if ( @_ ) {
+ return qsearch( 'cust_svc', { 'pkgnum' => $self->pkgnum,
+ 'svcpart' => shift, } );
+ }
+
#if ( $self->{'_svcnum'} ) {
# values %{ $self->{'_svcnum'}->cache };
#} else {
@@ -524,8 +531,45 @@ sub cust_svc {
$pkg_svc ? $pkg_svc->quantity : 0,
];
}
- qsearch ( 'cust_svc', { 'pkgnum' => $self->pkgnum } );
+ qsearch( 'cust_svc', { 'pkgnum' => $self->pkgnum } );
#}
+
+}
+
+=item num_cust_svc [ SVCPART ]
+
+Returns the number of provisioned services for this package. If a svcpart is
+specified, counts only the matching services.
+
+=cut
+
+sub num_cust_svc {
+ my $self = shift;
+ my $sql = 'SELECT COUNT(*) FROM cust_svc WHERE pkgnum = ?';
+ $sql .= ' AND svcpart = ?' if @_;
+ my $sth = dbh->prepare($sql) or die dbh->errstr;
+ $sth->execute($self->pkgnum, @_) or die $sth->errstr;
+ $sth->fetchrow_arrayref->[0];
+}
+
+=item available_part_svc
+
+Returns a list FS::part_svc objects representing services included in this
+package but not yet provisioned. Each FS::part_svc object also has an extra
+field, I<num_avail>, which specifies the number of available services.
+
+=cut
+
+sub available_part_svc {
+ my $self = shift;
+ grep { $_->num_avail > 0 }
+ map {
+ my $part_svc = $_->part_svc;
+ $part_svc->{'Hash'}{'num_avail'} = #evil encapsulation-breaking
+ $_->quantity - $self->num_cust_svc($_->svcpart);
+ $part_svc;
+ }
+ $self->part_pkg->pkg_svc;
}
=item labels
diff --git a/fs_selfservice/FS-SelfService/SelfService.pm b/fs_selfservice/FS-SelfService/SelfService.pm
index 2cda9fe..ae6d376 100644
--- a/fs_selfservice/FS-SelfService/SelfService.pm
+++ b/fs_selfservice/FS-SelfService/SelfService.pm
@@ -22,17 +22,21 @@ $socket .= '.'.$tag if defined $tag && length($tag);
'chfn' => 'passwd/passwd',
'chsh' => 'passwd/passwd',
'login' => 'MyAccount/login',
+ 'logout' => 'MyAccount/logout',
'customer_info' => 'MyAccount/customer_info',
- 'edit_info' => 'MyAccount/edit_info',
+ 'edit_info' => 'MyAccount/edit_info', #add to ss cgi!
'invoice' => 'MyAccount/invoice',
- 'list_invoices' => 'MyAccount/list_invoices',
- 'cancel' => 'MyAccount/cancel',
+ 'list_invoices' => 'MyAccount/list_invoices', #?
+ 'cancel' => 'MyAccount/cancel', #add to ss cgi!
'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',
+ 'list_pkgs' => 'MyAccount/list_pkgs', #add to ss cgi!
+ 'order_pkg' => 'MyAccount/order_pkg', #add to ss cgi!
+ 'cancel_pkg' => 'MyAccount/cancel_pkg', #add to ss cgi!
+ 'charge' => 'MyAccount/charge', #?
+ 'part_svc_info' => 'MyAccount/part_svc_info',
+ 'provision_acct' => 'MyAccount/provision_acct',
+ 'unprovision_svc' => 'MyAccount/unprovision_svc',
'signup_info' => 'Signup/signup_info',
'new_customer' => 'Signup/new_customer',
'agent_login' => 'Agent/agent_login',
@@ -466,9 +470,28 @@ Returns a hash reference containing customer package information. The hash refe
=over 4
+
=item cust_pkg HASHREF
-Array reference of hash references, each of which has the fields of a cust_pkg record (see L<FS::cust_pkg>). Note these are not FS::cust_pkg objects, but hash references of columns and values.
+Array reference of hash references, each of which has the fields of a cust_pkg
+record (see L<FS::cust_pkg>) as well as the fields below. Note these are not
+the internal FS:: objects, but hash references of columns and values.
+
+=item all fields of part_pkg (XXXpare this down to a secure subset)
+
+=item part_svc - An array of hash references, each of which has the following keys:
+
+=over 4
+
+=item all fields of part_svc (XXXpare this down to a secure subset)
+
+=item avail
+
+=back
+
+=item error
+
+Empty on success, or an error message on errors.
=back
@@ -1033,7 +1056,8 @@ END
=head1 RESELLER FUNCTIONS
Note: Resellers can also use the B<signup_info> and B<new_customer> functions
-with their active session.
+with their active session, and the B<customer_info> and B<order_pkg> functions
+with their active session and an additonal I<custnum> parameter.
=over 4
diff --git a/fs_selfservice/FS-SelfService/cgi/agent.cgi b/fs_selfservice/FS-SelfService/cgi/agent.cgi
index 2d948e7..6d2fd58 100644
--- a/fs_selfservice/FS-SelfService/cgi/agent.cgi
+++ b/fs_selfservice/FS-SelfService/cgi/agent.cgi
@@ -221,6 +221,10 @@ sub process_order_pkg {
my $results = '';
+ unless ( length($cgi->param('_password')) ) {
+ my $init_data = signup_info( 'session_id' => $session_id );
+ $results = { 'error' => $init_data->{msgcat}{empty_password} }
+ }
if ( $cgi->param('_password') ne $cgi->param('_password2') ) {
my $init_data = signup_info( 'session_id' => $session_id );
$results = { error => $init_data->{msgcat}{passwords_dont_match} };
diff --git a/fs_selfservice/FS-SelfService/cgi/delete_svc.html b/fs_selfservice/FS-SelfService/cgi/delete_svc.html
new file mode 100644
index 0000000..16054a7
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/delete_svc.html
@@ -0,0 +1,18 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<TABLE BORDER=0 CELLPADDING=4><TR>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+
+<%= if ( $error ) {
+ $OUT .= qq!<FONT SIZE="+1" COLOR="#ff0000">Error: $error</FONT>!;
+} else {
+ $OUT .= "<FONT SIZE=4>$svc removed.</FONT>";
+} %>
+
+</TD></TR></TABLE>
+<HR>
+<FONT SIZE="-2">powered by <a href="http://www.sisd.com/freeside">freeside</a></FONT>
+</BODY></HTML>
+
diff --git a/fs_selfservice/FS-SelfService/cgi/logout.html b/fs_selfservice/FS-SelfService/cgi/logout.html
new file mode 100644
index 0000000..0e774e9
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/logout.html
@@ -0,0 +1,5 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+You have been logged out.
+</BODY></HTML>
+
diff --git a/fs_selfservice/FS-SelfService/cgi/make_payment.html b/fs_selfservice/FS-SelfService/cgi/make_payment.html
index cf6d62e..3522c08 100644
--- a/fs_selfservice/FS-SelfService/cgi/make_payment.html
+++ b/fs_selfservice/FS-SelfService/cgi/make_payment.html
@@ -1,10 +1,9 @@
<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
<%= $url = "$selfurl?session=$session_id;action="; ''; %>
-<TABLE BORDER=0 CELLPADDING=4><TR><TD VALIGN="top" HEIGHT=384 BGCOLOR="#dddddd">
-<A HREF="<%= $url %>myaccount">MyAccount</A><BR>
-<!-- <A HREF="<%= $url %>other">SomethingElse</A><BR> -->
-</TD><TD VALIGN="top">
+<TABLE BORDER=0 CELLPADDING=4><TR>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
<FONT SIZE=4>Make a payment</FONT><BR><BR>
<FORM NAME="OneTrueForm" METHOD="POST" ACTION="<%=$selfurl%>" onSubmit="document.OneTrueForm.process.disabled=true">
<INPUT TYPE="hidden" NAME="session" VALUE="<%=$session_id%>">
diff --git a/fs_selfservice/FS-SelfService/cgi/myaccount.html b/fs_selfservice/FS-SelfService/cgi/myaccount.html
index f48fded..9997d70 100644
--- a/fs_selfservice/FS-SelfService/cgi/myaccount.html
+++ b/fs_selfservice/FS-SelfService/cgi/myaccount.html
@@ -1,10 +1,9 @@
<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
<%= $url = "$selfurl?session=$session_id;action="; ''; %>
-<TABLE BORDER=0 CELLPADDING=4><TR><TD VALIGN="top" HEIGHT=384 BGCOLOR="#dddddd">
-<A HREF="<%= $url %>myaccount">MyAccount</A><BR>
-<!-- <A HREF="<%= $url %>other">SomethingElse</A><BR> -->
-</TD><TD VALIGN="top">
+<TABLE BORDER=0 CELLPADDING=4><TR>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
Hello <%= $name %>!<BR><BR>
<%= $small_custview %>
@@ -15,7 +14,7 @@ Hello <%= $name %>!<BR><BR>
<%=
if ( @open_invoices ) {
$OUT .= '<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=2 BGCOLOR="#eeeeee">'.
- '<TR><TH BGCOLOR="#ff3333" COLSPAN=5>Open Invoices</TH><TD>';
+ '<TR><TH BGCOLOR="#ff6666" COLSPAN=5>Open Invoices</TH></TR>';
my $link = qq!<A HREF="<%= $url %>myaccount!;
my $col1 = "ffffff";
my $col2 = "dddddd";
diff --git a/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html b/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html
new file mode 100644
index 0000000..ba3b3f2
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html
@@ -0,0 +1,13 @@
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<TD VALIGN="top" HEIGHT=384 BGCOLOR="#dddddd">
+
+<A HREF="<%= $url %>myaccount">Overview</A><BR><BR>
+<!--A HREF="<%= $url %>change_bill"-->Change&nbsp;payment&nbsp;info</A>&nbsp;*<BR><BR>
+<!--A HREF="<%= $url %>change_ship"-->Change&nbsp;service&nbsp;address</A>&nbsp;*<BR><BR>
+<A HREF="<%= $url %>provision">Setup&nbsp;my&nbsp;services</A><BR><BR>
+<!--A HREF="<%= $url %>order"-->Purchase&nbsp;additional&nbsp;package</A>&nbsp;*<BR><BR>
+<!--<A HREF="<%= $url %>pw_list">Change&nbsp;password(s)</A>&nbsp;*<BR><BR>-->
+<A HREF="passwd.html">Change&nbsp;password(s)</A><BR><BR>
+<A HREF="<%= $url %>logout">Logout</A><BR><BR>
+*&nbsp;coming&nbsp;soon
+</TD>
diff --git a/fs_selfservice/FS-SelfService/cgi/payment_results.html b/fs_selfservice/FS-SelfService/cgi/payment_results.html
index 92c8cf5..44289de 100644
--- a/fs_selfservice/FS-SelfService/cgi/payment_results.html
+++ b/fs_selfservice/FS-SelfService/cgi/payment_results.html
@@ -1,10 +1,9 @@
<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
<%= $url = "$selfurl?session=$session_id;action="; ''; %>
-<TABLE BORDER=0 CELLPADDING=4><TR><TD VALIGN="top" HEIGHT=384 BGCOLOR="#dddddd">
-<A HREF="<%= $url %>myaccount">MyAccount</A><BR>
-<!-- <A HREF="<%= $url %>other">SomethingElse</A><BR> -->
-</TD><TD VALIGN="top">
+<TABLE BORDER=0 CELLPADDING=4><TR>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
<FONT SIZE=4>Payment results</FONT><BR><BR>
<%= if ( $error ) {
$OUT .= qq!<FONT SIZE="+1" COLOR="#ff0000">Error processing your payment: $error</FONT>!;
diff --git a/fs_selfservice/FS-SelfService/cgi/process_svc_acct.html b/fs_selfservice/FS-SelfService/cgi/process_svc_acct.html
new file mode 100644
index 0000000..7052059
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/process_svc_acct.html
@@ -0,0 +1,14 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<TABLE BORDER=0 CELLPADDING=4><TR>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+
+<FONT SIZE=4><%= $svc %> setup sucessfully.</FONT>
+
+</TD></TR></TABLE>
+<HR>
+<FONT SIZE="-2">powered by <a href="http://www.sisd.com/freeside">freeside</a></FONT>
+</BODY></HTML>
+
diff --git a/fs_selfservice/FS-SelfService/cgi/provision.html b/fs_selfservice/FS-SelfService/cgi/provision.html
new file mode 100644
index 0000000..326f902
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/provision.html
@@ -0,0 +1,77 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<TABLE BORDER=0 CELLPADDING=4><TR>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+<FONT SIZE=4>Setup services</FONT><BR><BR>
+
+<SCRIPT>
+function areyousure(href, message) {
+ if (confirm(message) == true)
+ window.location.href = href;
+}
+</SCRIPT>
+
+<%= foreach my $pkg (
+ grep { scalar(@{$_->{part_svc}})
+ || scalar(@{$_->{cust_svc}})
+ } @cust_pkg
+ ) {
+
+ $OUT .= '<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=2 BGCOLOR="#ffffff">'.
+ '<TR><TH BGCOLOR="#6666ff" COLSPAN=3>'.
+ $pkg->{'pkg'}.
+ '</TH></TR>';
+
+ my $col1 = "ffffff";
+ my $col2 = "dddddd";
+ my $col = $col1;
+
+ foreach my $cust_svc ( @{ $pkg->{cust_svc} } ) {
+ my $td = qq!<TD BGCOLOR="#$col"!;
+
+ $OUT .= '<TR>'.
+ "$td ALIGN=right>". $cust_svc->{label}[0]. ': </TD>'.
+ "$td><B>". $cust_svc->{label}[1]. '</B></TD>'.
+ "$td><FONT SIZE=-1>";
+
+ #if ( $cust_svc->{label}[2] eq 'svc_acct' ) {
+ # $OUT .= qq!(<A HREF="${url}changepw;svcnum=$cust_svc->{'svcnum'}">!.
+ # 'change&nbsp;pw) ';
+ #}
+
+ unless ( $cust_svc->{'svcnum'} == $svcnum ) {
+ $OUT .= qq!(<A HREF="javascript:areyousure('${url}delete_svc;svcnum=$cust_svc->{svcnum}', 'This will perminantly delete the $cust_svc->{label}[1] $cust_svc->{label}[0]. Are you sure?')">!.
+ 'delete</A>)';
+
+ }
+ $OUT .= '</FONT></TD></TR>';
+ $col = $col eq $col1 ? $col2 : $col1;
+ }
+
+ $OUT .= '<TR><TD COLSPAN=3 BGCOLOR="#000000"></TD></TR>'
+ if scalar(@{$pkg->{part_svc}}) && scalar(@{$pkg->{cust_svc}});
+
+ my $col = $col1;
+
+ foreach my $part_svc ( @{ $pkg->{part_svc} } ) {
+
+ my $td = qq!<TD BGCOLOR="#$col"!;
+
+ $OUT .= "<TR>$td COLSPAN=3>".
+ qq!<A HREF="${url}provision_svc;pkgnum=$pkg->{'pkgnum'};svcpart=$part_svc->{'svcpart'}">!.
+ 'Setup '. $part_svc->{'svc'}. '</A> '.
+ '('. $part_svc->{'num_avail'}. ' available)'.
+ '</TD></TR>';
+ $col = $col eq $col1 ? $col2 : $col1;
+ }
+
+ $OUT .= '</TABLE><BR>';
+
+} %>
+
+</TD></TR></TABLE>
+<HR>
+<FONT SIZE="-2">powered by <a href="http://www.sisd.com/freeside">freeside</a></FONT>
+</BODY></HTML>
diff --git a/fs_selfservice/FS-SelfService/cgi/provision_svc_acct.html b/fs_selfservice/FS-SelfService/cgi/provision_svc_acct.html
new file mode 100644
index 0000000..d18375c
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/provision_svc_acct.html
@@ -0,0 +1,66 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<TABLE BORDER=0 CELLPADDING=4><TR>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+<FONT SIZE=4>Setup <%= $svc %></FONT><BR><BR>
+
+<%= if ( $error ) {
+ $OUT .= qq!<FONT SIZE="+1" COLOR="#ff0000">Error setting up $svc: $error!.
+ '</FONT><BR><BR>';
+} ''; %>
+<FORM ACTION="<%= $selfurl %>" METHOD=POST>
+<INPUT TYPE="hidden" NAME="session" VALUE="<%= $session_id %>">
+<INPUT TYPE="hidden" NAME="action" VALUE="process_svc_acct">
+<INPUT TYPE="hidden" NAME="pkgnum" VALUE="<%= $pkgnum %>">
+<INPUT TYPE="hidden" NAME="svcpart" VALUE="<%= $svcpart %>">
+<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=2 BGCOLOR="#cccccc">
+<TR>
+ <TD ALIGN="right">Username</TD>
+ <TD><INPUT TYPE="text" NAME="username" VALUE="<%= $username %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password" VALUE="<%= $_password %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Re-enter Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password2" VALUE="<%= $_password2 %>"></TD>
+</TR>
+<%=
+ if ( $security_phrase ) {
+ $OUT .= <<ENDOUT;
+<TR>
+ <TD ALIGN="right">Security Phrase</TD>
+ <TD><INPUT TYPE="text" NAME="sec_phrase" VALUE="$sec_phrase">
+ </TD>
+</TR>
+ENDOUT
+ } else {
+ $OUT .= '<INPUT TYPE="hidden" NAME="sec_phrase" VALUE="">';
+ }
+%>
+<%=
+ if ( @svc_acct_pop ) {
+ $OUT .= '<TR><TD ALIGN="right">Access number</TD><TD>'.
+ popselector( 'popnum' => $popnum,
+ 'pops' => \@svc_acct_pop,
+ 'init_popstate' => $init_popstate,
+ 'popac' => $popac,
+ 'acstate' => $acstate,
+ ).
+ '</TD></TR>';
+ } else {
+ $OUT .= popselector(popnum=>$popnum, pops=>\@svc_acct_pop);
+ }
+%>
+</TABLE>
+<INPUT TYPE="submit" VALUE="Setup">
+</FORM>
+
+</TD></TR></TABLE>
+<HR>
+<FONT SIZE="-2">powered by <a href="http://www.sisd.com/freeside">freeside</a></FONT>
+</BODY></HTML>
+
diff --git a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi
index 6d6716d..d8e044a 100644
--- a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi
+++ b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi
@@ -6,8 +6,11 @@ use subs qw(do_template);
use CGI;
use CGI::Carp qw(fatalsToBrowser);
use Text::Template;
-use FS::SelfService qw( login customer_info invoice payment_info
- process_payment );
+use FS::SelfService qw( login customer_info invoice
+ payment_info process_payment
+ list_pkgs
+ part_svc_info provision_acct unprovision_svc
+ );
$template_dir = '.';
@@ -54,8 +57,9 @@ if ( $cgi->param('session') eq 'login' ) {
$session_id = $cgi->param('session');
+#order|pw_list XXX ???
$cgi->param('action') =~
- /^(myaccount|view_invoice|make_payment|payment_results)$/
+ /^(myaccount|view_invoice|make_payment|payment_results|logout|change_bill|change_ship|provision|provision_svc|process_svc_acct|delete_svc)$/
or die "unknown action ". $cgi->param('action');
my $action = $1;
@@ -167,6 +171,63 @@ sub payment_results {
}
+sub logout {
+ FS::SelfService::logout( 'session_id' => $session_id );
+}
+
+sub provision {
+ list_pkgs( 'session_id' => $session_id );
+}
+
+sub provision_svc {
+
+ my $result = part_svc_info(
+ 'session_id' => $session_id,
+ map { $_ => $cgi->param($_) } qw( pkgnum svcpart ),
+ );
+ die $result->{'error'} if exists $result->{'error'} && $result->{'error'};
+
+ $result->{'svcdb'} =~ /^svc_(.*)$/
+ #or return { 'error' => 'Unknown svcdb '. $result->{'svcdb'} };
+ or die 'Unknown svcdb '. $result->{'svcdb'};
+ $action .= "_$1";
+
+ $result;
+}
+
+sub process_svc_acct {
+
+ my $result = provision_acct (
+ 'session_id' => $session_id,
+ map { $_ => $cgi->param($_) } qw(
+ pkgnum svcpart username _password _password2 sec_phrase popnum )
+ );
+
+ if ( exists $result->{'error'} && $result->{'error'} ) {
+ warn "$result $result->{'error'}";
+ $action = 'provision_svc_acct';
+ return {
+ $cgi->Vars,
+ %{ part_svc_info( 'session_id' => $session_id,
+ map { $_ => $cgi->param($_) } qw( pkgnum svcpart )
+ )
+ },
+ 'error' => $result->{'error'},
+ };
+ } else {
+ warn "$result $result->{'error'}";
+ return $result;
+ }
+
+}
+
+sub delete_svc {
+ unprovision_svc(
+ 'session_id' => $session_id,
+ 'svcnum' => $cgi->param('svcnum'),
+ );
+}
+
#--
sub do_template {
@@ -175,6 +236,7 @@ sub do_template {
$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",
@@ -183,6 +245,28 @@ sub do_template {
or die $Text::Template::ERROR;
print $cgi->header( '-expires' => 'now' ),
- $template->fill_in( HASH => $fill_in );
+ $template->fill_in( PACKAGE => 'FS::SelfService::_selfservicecgi',
+ HASH => $fill_in
+ );
+}
+
+#*FS::SelfService::_selfservicecgi::include = \&Text::Template::fill_in_file;
+
+package FS::SelfService::_selfservicecgi;
+
+#use FS::SelfService qw(regionselector expselect popselector);
+use FS::SelfService qw(popselector);
+
+sub include {
+ my $name = shift;
+ my $template = new Text::Template( TYPE => 'FILE',
+ SOURCE => "$main::template_dir/$name.html",
+ DELIMITERS => [ '<%=', '%>' ],
+ UNTAINT => 1,
+ )
+ or die $Text::Template::ERROR;
+
+ $template->fill_in();
+
}
diff --git a/fs_selfservice/FS-SelfService/cgi/view_invoice.html b/fs_selfservice/FS-SelfService/cgi/view_invoice.html
index d2b012b..46f7318 100644
--- a/fs_selfservice/FS-SelfService/cgi/view_invoice.html
+++ b/fs_selfservice/FS-SelfService/cgi/view_invoice.html
@@ -1,12 +1,9 @@
<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
<%= $url = "$selfurl?session=$session_id;action="; ''; %>
-<TABLE BORDER=0 CELLPADDING=4><TR><TD VALIGN="top" HEIGHT=384 BGCOLOR="#dddddd">
-<A HREF="<%= $url %>myaccount">MyAccount</A><BR>
-<!-- <A HREF="<%= $url %>other">SomethingElse</A><BR> -->
-</TD><TD VALIGN="top">
-
-<A HREF="<%= $url %>myaccount"><-- back to MyAccount</A><BR><BR>
+<TABLE BORDER=0 CELLPADDING=4><TR>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
<FONT SIZE="-1"><PRE>
<%= $invoice_text %>
diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi
index 4497713..4ed30b8 100755
--- a/httemplate/view/cust_main.cgi
+++ b/httemplate/view/cust_main.cgi
@@ -897,28 +897,14 @@ sub get_packages {
$pkg{expire} = $cust_pkg->getfield('expire');
$pkg{cancel} = $cust_pkg->getfield('cancel');
- my %svcparts = ();
-
- foreach my $pkg_svc (
- qsearch('pkg_svc', { 'pkgpart' => $part_pkg->pkgpart })
- ) {
-
- next if ($pkg_svc->quantity == 0);
-
- my $part_svc = qsearchs('part_svc', { 'svcpart' => $pkg_svc->svcpart });
-
- my $svcpart = {};
- $svcpart->{svcpart} = $part_svc->svcpart;
- $svcpart->{svc} = $part_svc->svc;
- $svcpart->{svcdb} = $part_svc->svcdb;
- $svcpart->{quantity} = $pkg_svc->quantity;
- $svcpart->{count} = 0;
-
- $svcpart->{services} = [];
-
- $svcparts{$svcpart->{svcpart}} = $svcpart;
-
- }
+ my %svcparts = map {
+ $_->svcpart => {
+ $_->part_svc->hash,
+ 'quantity' => $_->quantity,
+ 'count' => $cust_pkg->num_cust_svc($_->svcpart),
+ #'services' => [],
+ };
+ } $part_pkg->pkg_svc;
foreach my $cust_svc ( $cust_pkg->cust_svc ) {
#warn "svcnum ". $cust_svc->svcnum. " / svcpart ". $cust_svc->svcpart. "\n";
@@ -930,18 +916,14 @@ sub get_packages {
#false laziness with above, to catch extraneous services. whole
#damn thing should be OO...
my $svcpart = ( $svcparts{$cust_svc->svcpart} ||= {
- 'svcpart' => $cust_svc->svcpart,
- 'svc' => $cust_svc->part_svc->svc,
- 'svcdb' => $cust_svc->part_svc->svcdb,
+ $cust_svc->part_svc->hash,
'quantity' => 0,
- 'count' => 0,
- 'services' => [],
+ 'count' => $cust_pkg->num_cust_svc($cust_svc->svcpart),
+ #'services' => [],
} );
push @{$svcpart->{services}}, $svc;
- $svcpart->{count}++;
-
}
$pkg{svcparts} = [ values %svcparts ];