big update for customer self-service: add provisioning/unprovisioning of purchased...
authorivan <ivan>
Thu, 15 Jul 2004 22:40:01 +0000 (22:40 +0000)
committerivan <ivan>
Thu, 15 Jul 2004 22:40:01 +0000 (22:40 +0000)
17 files changed:
FS/FS/ClientAPI/MyAccount.pm
FS/FS/ClientAPI/Signup.pm
FS/FS/cust_pkg.pm
fs_selfservice/FS-SelfService/SelfService.pm
fs_selfservice/FS-SelfService/cgi/agent.cgi
fs_selfservice/FS-SelfService/cgi/delete_svc.html [new file with mode: 0644]
fs_selfservice/FS-SelfService/cgi/logout.html [new file with mode: 0644]
fs_selfservice/FS-SelfService/cgi/make_payment.html
fs_selfservice/FS-SelfService/cgi/myaccount.html
fs_selfservice/FS-SelfService/cgi/myaccount_menu.html [new file with mode: 0644]
fs_selfservice/FS-SelfService/cgi/payment_results.html
fs_selfservice/FS-SelfService/cgi/process_svc_acct.html [new file with mode: 0644]
fs_selfservice/FS-SelfService/cgi/provision.html [new file with mode: 0644]
fs_selfservice/FS-SelfService/cgi/provision_svc_acct.html [new file with mode: 0644]
fs_selfservice/FS-SelfService/cgi/selfservice.cgi
fs_selfservice/FS-SelfService/cgi/view_invoice.html
httemplate/view/cust_main.cgi

index f51174e..639cb7b 100644 (file)
@@ -22,6 +22,7 @@ use FS::cust_pkg;
 use FS::ClientAPI; #hmm
 FS::ClientAPI->register_handlers(
   'MyAccount/login'            => \&login,
 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,
   '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/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 );
 );
 
 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;
 
 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" };
 
   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;
 
 1;
 
index 2e2b80f..81ed5e6 100644 (file)
@@ -128,7 +128,7 @@ sub new_customer {
     #return "Passwords don't match"
     #  if $hashref->{'_password'} ne $hashref->{'_password2'}
   return { 'error' => gettext('empty_password') }
     #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',{} ));
   # a bit inefficient for large numbers of pops
   return { 'error' => gettext('no_access_number_selected') }
     unless $packet->{'popnum'} || !scalar(qsearch('svc_acct_pop',{} ));
index fb41dfc..d2a48e9 100644 (file)
@@ -502,15 +502,22 @@ sub part_pkg {
     : qsearchs( 'part_pkg', { 'pkgpart' => $self->pkgpart } );
 }
 
     : 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
 
 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;
 
 =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 {
   #if ( $self->{'_svcnum'} ) {
   #  values %{ $self->{'_svcnum'}->cache };
   #} else {
@@ -524,8 +531,45 @@ sub cust_svc {
             $pkg_svc ? $pkg_svc->quantity : 0,
           ];
         }
             $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
 }
 
 =item labels
index 2cda9fe..ae6d376 100644 (file)
@@ -22,17 +22,21 @@ $socket .= '.'.$tag if defined $tag && length($tag);
   'chfn'                 => 'passwd/passwd',
   'chsh'                 => 'passwd/passwd',
   'login'                => 'MyAccount/login',
   'chfn'                 => 'passwd/passwd',
   'chsh'                 => 'passwd/passwd',
   'login'                => 'MyAccount/login',
+  'logout'               => 'MyAccount/logout',
   'customer_info'        => 'MyAccount/customer_info',
   'customer_info'        => 'MyAccount/customer_info',
-  'edit_info'            => 'MyAccount/edit_info',
+  'edit_info'            => 'MyAccount/edit_info',     #add to ss cgi!
   'invoice'              => 'MyAccount/invoice',
   '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',
   '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',
   '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
 
 
 =over 4
 
+
 =item cust_pkg HASHREF
 
 =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
 
 
 =back
 
@@ -1033,7 +1056,8 @@ END
 =head1 RESELLER FUNCTIONS
 
 Note: Resellers can also use the B<signup_info> and B<new_customer> functions
 =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
 
 
 =over 4
 
index 2d948e7..6d2fd58 100644 (file)
@@ -221,6 +221,10 @@ sub process_order_pkg {
 
   my $results = '';
 
 
   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} };
   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 (file)
index 0000000..16054a7
--- /dev/null
@@ -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 (file)
index 0000000..0e774e9
--- /dev/null
@@ -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>
+
index cf6d62e..3522c08 100644 (file)
@@ -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="; ''; %>
 <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%>">
 <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%>">
index f48fded..9997d70 100644 (file)
@@ -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="; ''; %>
 <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 %>
 
 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">'.
 <%=
   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";
     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 (file)
index 0000000..ba3b3f2
--- /dev/null
@@ -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>
index 92c8cf5..44289de 100644 (file)
@@ -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="; ''; %>
 <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>!;
 <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 (file)
index 0000000..7052059
--- /dev/null
@@ -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 (file)
index 0000000..326f902
--- /dev/null
@@ -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 (file)
index 0000000..d18375c
--- /dev/null
@@ -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>
+
index 6d6716d..d8e044a 100644 (file)
@@ -6,8 +6,11 @@ use subs qw(do_template);
 use CGI;
 use CGI::Carp qw(fatalsToBrowser);
 use Text::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 = '.';
 
 
 $template_dir = '.';
 
@@ -54,8 +57,9 @@ if ( $cgi->param('session') eq 'login' ) {
 
 $session_id = $cgi->param('session');
 
 
 $session_id = $cgi->param('session');
 
+#order|pw_list XXX ???
 $cgi->param('action') =~
 $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;
 
   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 {
 #--
 
 sub do_template {
@@ -175,6 +236,7 @@ sub do_template {
 
   $cgi->delete_all();
   $fill_in->{'selfurl'} = $cgi->self_url;
 
   $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",
 
   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' ),
     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();
+
 }
 
 }
 
index d2b012b..46f7318 100644 (file)
@@ -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="; ''; %>
 <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 %>
 
 <FONT SIZE="-1"><PRE>
 <%= $invoice_text %>
index 4497713..4ed30b8 100755 (executable)
@@ -897,28 +897,14 @@ sub get_packages {
     $pkg{expire} = $cust_pkg->getfield('expire');
     $pkg{cancel} = $cust_pkg->getfield('cancel');
   
     $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";
 
     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} ||= {
       #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,
         'quantity' => 0,
-        'count'    => 0,
-        'services' => [],
+        'count'    => $cust_pkg->num_cust_svc($cust_svc->svcpart),
+        #'services' => [],
       } );
 
       push @{$svcpart->{services}}, $svc;
 
       } );
 
       push @{$svcpart->{services}}, $svc;
 
-      $svcpart->{count}++;
-
     }
 
     $pkg{svcparts} = [ values %svcparts ];
     }
 
     $pkg{svcparts} = [ values %svcparts ];