signup w/globalpops DID selection via mason components pass-through
[freeside.git] / FS / FS / ClientAPI / Signup.pm
index b1cc3f0..aeb0aaa 100644 (file)
@@ -1,10 +1,13 @@
 package FS::ClientAPI::Signup;
 
 use strict;
+use vars qw($DEBUG $me);
+use Data::Dumper;
 use Tie::RefHash;
 use FS::Conf;
 use FS::Record qw(qsearch qsearchs dbdef);
 use FS::Msgcat qw(gettext);
+use FS::Misc qw(card_types);
 use FS::ClientAPI_SessionCache;
 use FS::agent;
 use FS::cust_main_county;
@@ -13,78 +16,122 @@ use FS::svc_acct_pop;
 use FS::cust_main;
 use FS::cust_pkg;
 use FS::svc_acct;
+use FS::svc_phone;
 use FS::acct_snarf;
 use FS::queue;
 use FS::reg_code;
 
+$DEBUG = 0;
+$me = '[FS::ClientAPI::Signup]';
+
 sub signup_info {
   my $packet = shift;
 
+  warn "$me signup_info called on $packet\n" if $DEBUG;
+
   my $conf = new FS::Conf;
+  my $svc_x = $conf->config('signup_server-service') || 'svc_acct';
 
-  use vars qw($signup_info); #cache for performance;
-  $signup_info ||= {
-    'cust_main_county' =>
-      [ map { $_->hashref } qsearch('cust_main_county', {}) ],
+  my $cache = new FS::ClientAPI_SessionCache( {
+    'namespace' => 'FS::ClientAPI::Signup',
+  } );
+  my $signup_info_cache = $cache->get('signup_info_cache');
 
-    'agent' =>
-      [
-        map { $_->hashref }
-          qsearch('agent', dbdef->table('agent')->column('disabled')
-                             ? { 'disabled' => '' }
-                             : {}
-                 )
-      ],
+  if ( $signup_info_cache ) {
 
-    'part_referral' =>
-      [
-        map { $_->hashref }
-          qsearch('part_referral',
-                    dbdef->table('part_referral')->column('disabled')
-                      ? { 'disabled' => '' }
-                      : {}
-                 )
-      ],
+    warn "$me loading cached signup info\n" if $DEBUG > 1;
+
+  } else {
 
-    'agentnum2part_pkg' =>
+    warn "$me populating signup info cache\n" if $DEBUG > 1;
+
+    my $agentnum2part_pkg = 
       {
         map {
           my $href = $_->pkgpart_hashref;
           $_->agentnum =>
             [
-              map { { 'payby' => [ $_->payby ], %{$_->hashref} } }
-                grep { $_->svcpart('svc_acct') && $href->{ $_->pkgpart } }
+              map { { 'payby'       => [ $_->payby ],
+                      'freq_pretty' => $_->freq_pretty,
+                      'options'     => { $_->options },
+                      %{$_->hashref}
+                  } }
+                grep { $_->svcpart($svc_x) && $href->{ $_->pkgpart } }
                   qsearch( 'part_pkg', { 'disabled' => '' } )
             ];
-        } qsearch('agent', dbdef->table('agent')->column('disabled')
-                             ? { 'disabled' => '' }
-                             : {}
-                 )
-      },
+        } qsearch('agent', { 'disabled' => '' })
+      };
+
+    my $msgcat = { map { $_=>gettext($_) }
+                       qw( passwords_dont_match invalid_card unknown_card_type
+                           not_a empty_password illegal_or_empty_text )
+                 };
+    warn "msgcat: ". Dumper($msgcat). "\n" if $DEBUG > 2;
+
+    my $label = { map { $_ => FS::Msgcat::_gettext($_) }
+                      qw( stateid stateid_state )
+                };
+    warn "label: ". Dumper($label). "\n" if $DEBUG > 2;
+
+    $signup_info_cache = {
+      'cust_main_county' => [ map $_->hashref,
+                                  qsearch('cust_main_county', {} )
+                            ],
+
+      'agent' => [ map $_->hashref,
+                       qsearch('agent', { 'disabled' => '' } )
+                 ],
+
+      'part_referral' => [ map $_->hashref,
+                               qsearch('part_referral', { 'disabled' => '' } )
+                         ],
+
+      'agentnum2part_pkg' => $agentnum2part_pkg,
+
+      'svc_acct_pop' => [ map $_->hashref, qsearch('svc_acct_pop',{} ) ],
+
+      'emailinvoiceonly' => $conf->exists('emailinvoiceonly'),
 
-    'svc_acct_pop' => [ map { $_->hashref } qsearch('svc_acct_pop',{} ) ],
+      'security_phrase' => $conf->exists('security_phrase'),
 
-    'emailinvoiceonly' => $conf->exists('emailinvoiceonly'),
+      'payby' => [ $conf->config('signup_server-payby') ],
 
-    'security_phrase' => $conf->exists('security_phrase'),
+      'card_types' => card_types(),
 
-    'payby' => [ $conf->config('signup_server-payby') ],
+      'paytypes' => [ @FS::cust_main::paytypes ],
 
-    'cvv_enabled' => defined dbdef->table('cust_main')->column('paycvv'),
+      'cvv_enabled' => 1,
 
-    'ship_enabled' => defined dbdef->table('cust_main')->column('ship_last'),
+      'stateid_enabled' => $conf->exists('show_stateid'),
 
-    'msgcat' => { map { $_=>gettext($_) } qw(
-      passwords_dont_match invalid_card unknown_card_type not_a empty_password illegal_or_empty_text
-    ) },
+      'paystate_enabled' => $conf->exists('show_bankstate'),
 
-    'statedefault' => $conf->config('statedefault') || 'CA',
+      'ship_enabled' => 1,
 
-    'countrydefault' => $conf->config('countrydefault') || 'US',
+      'msgcat' => $msgcat,
 
-    'refnum' => $conf->config('signup_server-default_refnum'),
+      'label' => $label,
 
-  };
+      'statedefault' => scalar($conf->config('statedefault')) || 'CA',
+
+      'countrydefault' => scalar($conf->config('countrydefault')) || 'US',
+
+      'refnum' => scalar($conf->config('signup_server-default_refnum')),
+
+      'default_pkgpart' => scalar($conf->config('signup_server-default_pkgpart')),
+
+      'signup_service' => $svc_x,
+      'default_svcpart' => scalar($conf->config('signup_server-default_svcpart')),
+
+    };
+
+    $cache->set('signup_info_cache', $signup_info_cache);
+
+  }
+
+  my $signup_info = { %$signup_info_cache };
+  warn "$me signup info loaded\n" if $DEBUG > 1;
+  warn Dumper($signup_info). "\n" if $DEBUG > 2;
 
   my @addl = qw( signup_server-classnum2 signup_server-classnum3 );
 
@@ -93,18 +140,36 @@ sub signup_info {
     $signup_info->{optional_packages} = [];
 
     foreach my $addl ( @addl ) {
+
+      warn "$me adding optional package info\n" if $DEBUG > 1;
+
       my $classnum = $conf->config($addl) or next;
-      my @pkgs = map { $_->hashref }
+
+      my @pkgs = map { {
+                         'freq_pretty' => $_->freq_pretty,
+                         'options'     => { $_->options },
+                         %{ $_->hashref }
+                       };
+                     }
                      qsearch( 'part_pkg', { classnum => $classnum } );
+
       push @{$signup_info->{optional_packages}}, \@pkgs;
+
+      warn "$me done adding opt. package info for $classnum\n" if $DEBUG > 1;
+
     }
 
   }
 
-  my $agentnum = $conf->config('signup_server-default_agentnum');
+  my $agentnum = $packet->{'agentnum'}
+                 || $conf->config('signup_server-default_agentnum');
+  $agentnum =~ /^(\d*)$/ or die "illegal agentnum";
+  $agentnum = $1;
 
   my $session = '';
   if ( exists $packet->{'session_id'} ) {
+
+    warn "$me loading agent session\n" if $DEBUG > 1;
     my $cache = new FS::ClientAPI_SessionCache( {
       'namespace' => 'FS::ClientAPI::Agent',
     } );
@@ -114,14 +179,41 @@ sub signup_info {
     } else {
       return { 'error' => "Can't resume session" }; #better error message
     }
+    warn "$me done loading agent session\n" if $DEBUG > 1;
+
+  } elsif ( exists $packet->{'customer_session_id'} ) {
+
+    warn "$me loading customer session\n" if $DEBUG > 1;
+    my $cache = new FS::ClientAPI_SessionCache( {
+      'namespace' => 'FS::ClientAPI::MyAccount',
+    } );
+    $session = $cache->get($packet->{'customer_session_id'});
+    if ( $session ) {
+      my $custnum = $session->{'custnum'};
+      my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum });
+      return { 'error' => "Can't find your customer record" } unless $cust_main;
+      $agentnum = $cust_main->agentnum;
+    } else {
+      return { 'error' => "Can't resume session" }; #better error message
+    }
+    warn "$me done loading customer session\n" if $DEBUG > 1;
+
   }
 
   $signup_info->{'part_pkg'} = [];
 
   if ( $packet->{'reg_code'} ) {
+
+    warn "$me setting package list via reg_code\n" if $DEBUG > 1;
+
     $signup_info->{'part_pkg'} = 
-      [ map { { 'payby'   => [ $_->payby ], %{$_->hashref} } }
-          grep { $_->svcpart('svc_acct') }
+      [ map { { 'payby'       => [ $_->payby ],
+                'freq_pretty' => $_->freq_pretty,
+                'options'     => { $_->options },
+                %{$_->hashref}
+              };
+            }
+          grep { $_->svcpart($svc_x) }
           map { $_->part_pkg }
             qsearchs( 'reg_code', { 'code'     => $packet->{'reg_code'},
                                     'agentnum' => $agentnum,              } )
@@ -131,11 +223,19 @@ sub signup_info {
     $signup_info->{'error'} = 'Unknown registration code'
       unless @{ $signup_info->{'part_pkg'} };
 
+    warn "$me done setting package list via reg_code\n" if $DEBUG > 1;
+
   } elsif ( $packet->{'promo_code'} ) {
 
+    warn "$me setting package list via promo_code\n" if $DEBUG > 1;
+
     $signup_info->{'part_pkg'} =
-      [ map { { 'payby'   => [ $_->payby ], %{$_->hashref} } }
-          grep { $_->svcpart('svc_acct') }
+      [ map { { 'payby'   => [ $_->payby ],
+                'freq_pretty' => $_->freq_pretty,
+                'options'     => { $_->options },
+                %{$_->hashref}
+            } }
+          grep { $_->svcpart($svc_x) }
             qsearch( 'part_pkg', { 'promo_code' => {
                                      op=>'ILIKE',
                                      value=>$packet->{'promo_code'}
@@ -145,16 +245,43 @@ sub signup_info {
 
     $signup_info->{'error'} = 'Unknown promotional code'
       unless @{ $signup_info->{'part_pkg'} };
+
+    warn "$me done setting package list via promo_code\n" if $DEBUG > 1;
   }
 
-  if ( $agentnum && ! @{ $signup_info->{'part_pkg'} } ) {
-    $signup_info->{'part_pkg'} = $signup_info->{'agentnum2part_pkg'}{$agentnum};
+  if ( $agentnum ) {
+
+    warn "$me setting agent-specific package list\n" if $DEBUG > 1;
+    $signup_info->{'part_pkg'} = $signup_info->{'agentnum2part_pkg'}{$agentnum}
+      unless @{ $signup_info->{'part_pkg'} };
+    warn "$me done setting agent-specific package list\n" if $DEBUG > 1;
+
+    warn "$me setting agent-specific adv. source list\n" if $DEBUG > 1;
+    $signup_info->{'part_referral'} =
+      [
+        map { $_->hashref }
+          qsearch( {
+                     'table'     => 'part_referral',
+                     'hashref'   => { 'disabled' => '' },
+                     'extra_sql' => "AND (    agentnum = $agentnum  ".
+                                    "      OR agentnum IS NULL    ) ",
+                   },
+                 )
+      ];
+    warn "$me done setting agent-specific adv. source list\n" if $DEBUG > 1;
+
   }
   # else {
   # delete $signup_info->{'part_pkg'};
   #}
 
-  if ( $session ) {
+  warn "$me sorting package list\n" if $DEBUG > 1;
+  $signup_info->{'part_pkg'} = [ sort { $a->{pkg} cmp $b->{pkg} }  # case?
+                                      @{ $signup_info->{'part_pkg'} }
+                               ];
+  warn "$me done sorting package list\n" if $DEBUG > 1;
+
+  if ( exists $packet->{'session_id'} ) {
     my $agent_signup_info = { %$signup_info };
     delete $agent_signup_info->{agentnum2part_pkg};
     $agent_signup_info->{'agent'} = $session->{'agent'};
@@ -165,19 +292,50 @@ sub signup_info {
 
 }
 
+sub domain_select_hash {
+  my $packet = shift;
+
+  my $response = {};
+
+  if ($packet->{pkgpart}) {
+    my $part_pkg = qsearchs('part_pkg' => { 'pkgpart' => $packet->{pkgpart} } );
+    #$packet->{svcpart} = $part_pkg->svcpart('svc_acct')
+    $packet->{svcpart} = $part_pkg->svcpart
+      if $part_pkg;
+  }
+
+  if ($packet->{svcpart}) {
+    my $part_svc = qsearchs('part_svc' => { 'svcpart' => $packet->{svcpart} } );
+    $response->{'domsvc'} = $part_svc->part_svc_column('domsvc')->columnvalue
+      if ($part_svc && $part_svc->part_svc_column('domsvc')->columnflag  eq 'D');
+  }
+
+  $response->{'domains'}
+    = { domain_select_hash FS::svc_acct( map { $_ => $packet->{$_} }
+                                                 qw(svcpart pkgnum)
+                                       ) };
+
+  $response;
+}
+
 sub new_customer {
   my $packet = shift;
 
   my $conf = new FS::Conf;
+  my $svc_x = $conf->config('signup_server-service') || 'svc_acct';
+
+  if ( $svc_x eq 'svc_acct' ) {
   
-  #things that aren't necessary in base class, but are for signup server
-    #return "Passwords don't match"
-    #  if $hashref->{'_password'} ne $hashref->{'_password2'}
-  return { 'error' => gettext('empty_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',{} ));
+    #things that aren't necessary in base class, but are for signup server
+      #return "Passwords don't match"
+      #  if $hashref->{'_password'} ne $hashref->{'_password2'}
+    return { 'error' => gettext('empty_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',{} ));
+
+  }
 
   my $agentnum;
   if ( exists $packet->{'session_id'} ) {
@@ -207,14 +365,14 @@ sub new_customer {
 
       last first ss company address1 address2
       city county state zip country
-      daytime night fax
+      daytime night fax stateid stateid_state
 
       ship_last ship_first ship_ss ship_company ship_address1 ship_address2
       ship_city ship_county ship_state ship_zip ship_country
       ship_daytime ship_night ship_fax
 
       payby
-      payinfo paycvv paydate payname
+      payinfo paycvv paydate payname paystate paytype
       paystart_month paystart_year payissue
       payip
 
@@ -230,7 +388,9 @@ sub new_customer {
   $cust_main->payinfo($cust_main->daytime)
     if $cust_main->payby eq 'LECB' && ! $cust_main->payinfo;
 
-  my @invoicing_list = split( /\s*\,\s*/, $packet->{'invoicing_list'} );
+  my @invoicing_list = $packet->{'invoicing_list'}
+                         ? split( /\s*\,\s*/, $packet->{'invoicing_list'} )
+                         : ();
 
   $packet->{'pkgpart'} =~ /^(\d+)$/ or '' =~ /^()$/;
   my $pkgpart = $1;
@@ -239,7 +399,7 @@ sub new_customer {
   my $part_pkg =
     qsearchs( 'part_pkg', { 'pkgpart' => $pkgpart } )
       or return { 'error' => "WARNING: unknown pkgpart: $pkgpart" };
-  my $svcpart = $part_pkg->svcpart('svc_acct');
+  my $svcpart = $part_pkg->svcpart($svc_x);
 
   my $reg_code = '';
   if ( $packet->{'reg_code'} ) {
@@ -257,31 +417,47 @@ sub new_customer {
   #my $error = $cust_pkg->check;
   #return { 'error' => $error } if $error;
 
-  my $svc_acct = new FS::svc_acct ( {
-    'svcpart'   => $svcpart,
-    map { $_ => $packet->{$_} }
-      qw( username _password sec_phrase popnum ),
-  } );
+  #should be all auto-magic and shit
+  my $svc;
+  if ( $svc_x eq 'svc_acct' ) {
+
+    my $svc = new FS::svc_acct ( {
+      'svcpart'   => $svcpart,
+      map { $_ => $packet->{$_} }
+        qw( username _password sec_phrase popnum ),
+    } );
+
+    my @acct_snarf;
+    my $snarfnum = 1;
+    while (    exists($packet->{"snarf_machine$snarfnum"})
+            && length($packet->{"snarf_machine$snarfnum"}) ) {
+      my $acct_snarf = new FS::acct_snarf ( {
+        'machine'   => $packet->{"snarf_machine$snarfnum"},
+        'protocol'  => $packet->{"snarf_protocol$snarfnum"},
+        'username'  => $packet->{"snarf_username$snarfnum"},
+        '_password' => $packet->{"snarf_password$snarfnum"},
+      } );
+      $snarfnum++;
+      push @acct_snarf, $acct_snarf;
+    }
+    $svc->child_objects( \@acct_snarf );
+
+  } elsif ( $svc_x eq 'svc_phone' ) {
 
-  my @acct_snarf;
-  my $snarfnum = 1;
-  while (    exists($packet->{"snarf_machine$snarfnum"})
-          && length($packet->{"snarf_machine$snarfnum"}) ) {
-    my $acct_snarf = new FS::acct_snarf ( {
-      'machine'   => $packet->{"snarf_machine$snarfnum"},
-      'protocol'  => $packet->{"snarf_protocol$snarfnum"},
-      'username'  => $packet->{"snarf_username$snarfnum"},
-      '_password' => $packet->{"snarf_password$snarfnum"},
+    my $svc = new FS::svc_phone ( {
+      'svcpart' => $svcpart,
+       map { $_ => $packet->{$_} }
+         qw( countrycode phonenum pin ),
     } );
-    $snarfnum++;
-    push @acct_snarf, $acct_snarf;
+
+  } else {
+    die "unknown signup service $svc_x";
   }
-  $svc_acct->child_objects( \@acct_snarf );
 
-  my $y = $svc_acct->setdefault; # arguably should be in new method
+  my $y = $svc->setdefault; # arguably should be in new method
   return { 'error' => $y } if $y && !ref($y);
 
-  #$error = $svc_acct->check;
+  #$error = $svc->check;
   #return { 'error' => $error } if $error;
 
   #setup a job dependancy to delay provisioning
@@ -294,7 +470,7 @@ sub new_customer {
 
   use Tie::RefHash;
   tie my %hash, 'Tie::RefHash';
-  %hash = ( $cust_pkg => [ $svc_acct ] );
+  %hash = ( $cust_pkg => [ $svc ] );
   #msgcat
   $error = $cust_main->insert(
     \%hash,
@@ -315,8 +491,10 @@ sub new_customer {
     #warn "[fs_signup_server] error billing new customer: $bill_error"
     #  if $bill_error;
 
-    $cust_main->apply_payments;
-    $cust_main->apply_credits;
+    $bill_error = $cust_main->apply_payments_and_credits;
+    #warn "[fs_signup_server] error applying payments and credits for".
+    #     " new customer: $bill_error"
+    #  if $bill_error;
 
     $bill_error = $cust_main->collect('realtime' => 1);
     #warn "[fs_signup_server] error collecting from new customer: $bill_error"
@@ -325,7 +503,9 @@ sub new_customer {
     if ( $cust_main->balance > 0 ) {
 
       #this makes sense.  credit is "un-doing" the invoice
-      $cust_main->credit( $cust_main->balance, 'signup server decline' );
+      $cust_main->credit( $cust_main->balance, 'signup server decline',
+                          'reason_type' => $conf->config('signup_credit_type'),
+                        );
       $cust_main->apply_credits;
 
       #should check list for errors...