big update for reseller interface
[freeside.git] / FS / FS / ClientAPI / MyAccount.pm
index 58ab6c0..34dad38 100644 (file)
@@ -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,26 +96,21 @@ sub login {
          };
 }
 
-sub customer_info {
+sub logout {
   my $p = shift;
-
-  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'};
+    $cache->remove($p->{'session_id'});
+    return { 'error' => '' };
   } else {
     return { 'error' => "Can't resume session" }; #better error message
   }
+}
+
+sub customer_info {
+  my $p = shift;
+
+  my($context, $session, $custnum) = _custoragent_session_custnum($p);
+  return { 'error' => $session } if $context eq 'error';
 
   my %return;
   if ( $custnum ) { #customer record
@@ -212,7 +211,41 @@ sub payment_info {
   my $session = $cache->get($p->{'session_id'})
     or return { 'error' => "Can't resume session" }; #better error message
 
-  my %return;
+  ##
+  #generic
+  ##
+
+  my $conf = new FS::Conf;
+  my %states = map { $_->state => 1 }
+                 qsearch('cust_main_county', {
+                   'country' => $conf->config('defaultcountry') || 'US'
+                 } );
+
+  use vars qw($payment_info); #cache for performance
+  $payment_info ||= {
+
+    #list all counties/states/countries
+    'cust_main_county' => 
+      [ map { $_->hashref } qsearch('cust_main_county', {}) ],
+
+    #shortcut for one-country folks
+    'states' =>
+      [ sort { $a cmp $b } keys %states ],
+
+    'card_types' => {
+      'VISA' => 'VISA card',
+      'MasterCard' => 'MasterCard',
+      'Discover' => 'Discover card',
+      'American Express' => 'American Express card',
+    },
+
+  };
+
+  ##
+  #customer-specific
+  ##
+
+  my %return = %$payment_info;
 
   my $custnum = $session->{'custnum'};
 
@@ -236,25 +269,7 @@ sub payment_info {
 
   }
 
-  #list all counties/states/countries
-  $return{'cust_main_county'} = 
-      [ map { $_->hashref } qsearch('cust_main_county', {}) ];
-
-  #shortcut for one-country folks
-  my $conf = new FS::Conf;
-  my %states = map { $_->state => 1 }
-                 qsearch('cust_main_county', {
-                   'country' => $conf->config('defaultcountry') || 'US'
-                 } );
-  $return{'states'} = [ sort { $a cmp $b } keys %states ];
-
-  $return{card_types} = {
-    'VISA' => 'VISA card',
-    'MasterCard' => 'MasterCard',
-    'Discover' => 'Discover card',
-    'American Express' => 'American Express card',
-  };
-
+  #doubleclick protection
   my $_date = time;
   $return{paybatch} = "webui-MyAccount-$_date-$$-". rand() * 2**32;
 
@@ -421,43 +436,54 @@ sub cancel {
 
 sub list_pkgs {
   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($context, $session, $custnum) = _custoragent_session_custnum($p);
+  return { 'error' => $session } if $context eq 'error';
 
-  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 { 'cust_pkg' => [ map { $_->hashref } $cust_main->ncancelled_pkgs ] };
+  #return { 'cust_pkg' => [ map { $_->hashref } $cust_main->ncancelled_pkgs ] };
+
+  my $conf = new FS::Conf;
+
+  { 'svcnum'   => $session->{'svcnum'},
+    'custnum'  => $custnum,
+    'cust_pkg' => [ map {
+                          { $_->hash,
+                            $_->part_pkg->hash,
+                            part_svc =>
+                              [ map $_->hashref, $_->available_part_svc ],
+                            cust_svc => 
+                              [ map { my $ref = { $_->hash,
+                                                  label => [ $_->label ],
+                                                };
+                                      $ref->{_password} = $_->svc_x->_password
+                                        if $context eq 'agent'
+                                        && $conf->exists('agent-showpasswords')
+                                        && $_->part_svc->svcdb eq 'svc_acct';
+                                      $ref;
+                                    } $_->cust_svc
+                              ],
+                          };
+                        } $cust_main->ncancelled_pkgs
+                  ],
+    'small_custview' =>
+      small_custview( $cust_main, $conf->config('defaultcountry') ),
+  };
 
 }
 
 sub order_pkg {
   my $p = shift;
 
-  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($context, $session, $custnum) = _custoragent_session_custnum($p);
+  return { 'error' => $session } if $context eq 'error';
 
   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" };
 
@@ -539,7 +565,8 @@ sub order_pkg {
     $cust_main->apply_credits;
     $bill_error = $cust_main->collect;
 
-    if ( $cust_main->balance > $old_balance
+    if (    $cust_main->balance > $old_balance
+         && $cust_main->balance > 0
          && $cust_main->payby !~ /^(BILL|DCRD|DCHK)$/ ) {
       #this makes sense.  credit is "un-doing" the invoice
       $cust_main->credit( sprintf("%.2f", $cust_main->balance - $old_balance ),
@@ -547,7 +574,7 @@ sub order_pkg {
       $cust_main->apply_credits( 'order' => 'newest' );
 
       $cust_pkg->cancel('quiet'=>1);
-      return { 'error' => '_decline' };
+      return { 'error' => '_decline', 'bill_error' => $bill_error };
     } else {
       $cust_pkg->reexport;
     }
@@ -581,5 +608,153 @@ sub cancel_pkg {
 
 }
 
+sub provision_acct {
+  my $p = shift;
+
+  my($context, $session, $custnum) = _custoragent_session_custnum($p);
+  return { 'error' => $session } if $context eq 'error';
+
+  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" };
+
+  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($context, $session, $custnum) = _custoragent_session_custnum($p);
+  return { 'error' => $session } if $context eq 'error';
+
+  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" };
+
+  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;
+
+  my $conf = new FS::Conf;
+
+  return {
+    'svc'     => $part_svc->svc,
+    'svcdb'   => $part_svc->svcdb,
+    'pkgnum'  => $pkgnum,
+    'svcpart' => $svcpart,
+    'custnum' => $custnum,
+
+    'security_phrase' => 0, #XXX !
+    'svc_acct_pop'    => [], #XXX !
+    'popnum'          => '',
+    'init_popstate'   => '',
+    'popac'           => '',
+    'acstate'         => '',
+
+    'small_custview' =>
+      small_custview( $cust_main, $conf->config('defaultcountry') ),
+
+  };
+
+}
+
+sub unprovision_svc {
+  my $p = shift;
+
+  my($context, $session, $custnum) = _custoragent_session_custnum($p);
+  return { 'error' => $session } if $context eq 'error';
+
+  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" };
+
+  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;
+
+  my $conf = new FS::Conf;
+
+  return { 'svc'   => $cust_svc->part_svc->svc,
+           'error' => $cust_svc->cancel,
+           'small_custview' =>
+             small_custview( $cust_main, $conf->config('defaultcountry') ),
+         };
+
+}
+
+#--
+
+sub _custoragent_session_custnum {
+  my $p = shift;
+
+  my($context, $session, $custnum);
+  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
+  }
+
+  ($context, $session, $custnum);
+
+}
+
+
 1;