new_customer_minimal accepts address, & doc it, RT#34084
[freeside.git] / FS / FS / ClientAPI / Signup.pm
index f17752a..e1ee6cd 100644 (file)
@@ -23,6 +23,7 @@ use FS::queue;
 use FS::reg_code;
 use FS::payby;
 use FS::banned_pay;
+use FS::part_tag;
 
 $DEBUG = 0;
 $me = '[FS::ClientAPI::Signup]';
@@ -98,7 +99,7 @@ sub signup_info {
 
     my @signup_bools = qw( no_company recommend_daytime recommend_email );
 
-    my @signup_server_scalars = qw( default_pkgpart default_svcpart );
+    my @signup_server_scalars = qw( default_pkgpart default_svcpart default_domsvc );
 
     my @selfservice_textareas = qw( head body_header body_footer );
 
@@ -174,8 +175,10 @@ sub signup_info {
       'card_types'         => card_types(),
       'paytypes'           => [ @FS::cust_main::paytypes ],
       'cvv_enabled'        => 1,
+      'require_cvv'        => $conf->exists('signup-require_cvv'),
       'stateid_enabled'    => $conf->exists('show_stateid'),
       'paystate_enabled'   => $conf->exists('show_bankstate'),
+      'exempt_groups'      => [ grep /\S/, $conf->config('tax-cust_exempt-groups') ],
       'ship_enabled'       => 1,
       'msgcat'             => $msgcat,
       'label'              => $label,
@@ -405,8 +408,8 @@ sub signup_info {
            && $agent->agent_cust_main ) {
 
         my $cust_main = $agent->agent_cust_main;
-        my $prefix = length($cust_main->ship_last) ? 'ship_' : '';
-        $signup_info_cache_agent->{"ship_$_"} = $cust_main->get("$prefix$_")
+        my $location = $cust_main->ship_location;
+        $signup_info_cache_agent->{"ship_$_"} = $location->get($_)
           foreach qw( address1 city county state zip country );
 
       }
@@ -509,8 +512,37 @@ sub new_customer {
                 || $conf->config('signup_server-default_agentnum');
   }
 
+  my ($bill_hash, $ship_hash);
+  foreach my $f (FS::cust_main->location_fields) {
+    # avoid having to change this in front-end code
+    $bill_hash->{$f} = $packet->{"bill_$f"} || $packet->{$f};
+    $ship_hash->{$f} = $packet->{"ship_$f"};
+  }
+
   #shares some stuff with htdocs/edit/process/cust_main.cgi... take any
   # common that are still here and library them.
+
+  my %cust_main = (
+    'agentnum' => $agentnum,
+    'refnum'   => $packet->{refnum}
+                  || $conf->config('signup_server-default_refnum'),
+    'tagnum'   => [ FS::part_tag->default_tags ],
+
+    ( map { $_ => $packet->{$_} } qw(
+            salesnum
+            ss stateid stateid_state
+
+            payby
+            payinfo paycvv paydate payname paystate paytype
+            paystart_month paystart_year payissue
+            payip
+
+            referral_custnum comments
+          )
+    ),
+
+  );
+
   my $template_custnum = $conf->config('signup_server-prepaid-template-custnum');
   my $cust_main;
   if ( $template_custnum && $packet->{prepaid_shortform} ) {
@@ -518,79 +550,55 @@ sub new_customer {
     my $template_cust = qsearchs('cust_main', { 'custnum' => $template_custnum } );
     return { 'error' => 'Configuration error' } unless $template_cust;
     $cust_main = new FS::cust_main ( {
-      'agentnum'      => $agentnum,
-      'refnum'        => $packet->{refnum}
-                         || $conf->config('signup_server-default_refnum'),
-
-      ( map { $_ => $template_cust->$_ } qw( 
-              last first company address1 address2 
-              city county state zip country
-              daytime night fax 
-
-              ship_last ship_first ship_company ship_address1 ship_address2
-              ship_city ship_county ship_state ship_zip ship_country
-              ship_daytime ship_night ship_fax
-            )
+      %cust_main,
+      map { $_ => $template_cust->$_ } qw( 
+        last first company daytime night fax mobile
       ),
-
-      ( map { $_ => $packet->{$_} } qw(
-              ss stateid stateid_state
-
-              payby
-              payinfo paycvv paydate payname paystate paytype
-              paystart_month paystart_year payissue
-              payip
-
-              referral_custnum comments
-            )
-      ),
-
     } );
 
+    $bill_hash = { $template_cust->bill_location->location_hash };
+    $ship_hash = { $template_cust->ship_location->location_hash };
+
   } else {
 
     $cust_main = new FS::cust_main ( {
-      #'custnum'          => '',
-      'agentnum'      => $agentnum,
-      'refnum'        => $packet->{refnum}
-                         || $conf->config('signup_server-default_refnum'),
-
+      %cust_main,
       map { $_ => $packet->{$_} } qw(
-
-        last first ss company address1 address2
-        city county state zip country
-        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 paystate paytype
-        paystart_month paystart_year payissue
-        payip
+        last first company daytime night fax mobile
         override_ban_warn
-
-        referral_custnum comments
-      )
-
+      ),
     } );
   }
 
+  my $bill_location = FS::cust_location->new($bill_hash);
+  my $ship_location;
   my $agent = qsearchs('agent', { 'agentnum' => $agentnum } );
   if ( $conf->exists('agent-ship_address', $agentnum) 
     && $agent->agent_custnum ) {
 
     my $agent_cust_main = $agent->agent_cust_main;
     my $prefix = length($agent_cust_main->ship_last) ? 'ship_' : '';
-    $cust_main->set("ship_$_", $agent_cust_main->get("$prefix$_") )
-      foreach qw( address1 city county state zip country );
-
-    $cust_main->set("ship_$_", $cust_main->get($_))
-      foreach qw( last first );
+    $ship_location = FS::cust_location->new({ 
+        $agent_cust_main->ship_location->location_hash
+    });
 
   }
+  # we don't have an equivalent of the "same" checkbox in selfservice
+  # so is there a ship address, and if so, is it different from the billing 
+  # address?
+  elsif ( length($ship_hash->{address1}) > 0 and
+          grep { $bill_hash->{$_} ne $ship_hash->{$_} } keys(%$ship_hash)
+         ) {
+
+    $ship_location = FS::cust_location->new( $ship_hash );
+  
+  }
+  else {
+    $ship_location = $bill_location;
+  }
 
+  $cust_main->set('bill_location' => $bill_location);
+  $cust_main->set('ship_location' => $ship_location);
 
   return { 'error' => "Illegal payment type" }
     unless grep { $_ eq $packet->{'payby'} }
@@ -616,17 +624,40 @@ sub new_customer {
                                     );
     }
 
-    $cust_main->payby('BILL')   # MCRD better?
+    $cust_main->payby('BILL')   # MCRD better?  no, that's for something else
       if $gw && $gw->gateway_namespace eq 'Business::OnlineThirdPartyPayment';
   }
 
+  return { 'error' => "CVV2 is required" }
+    if $cust_main->payby =~ /^(CARD|DCRD)$/
+    && ! $cust_main->paycvv
+    && $conf->exists('signup-require_cvv');
+
   $cust_main->payinfo($cust_main->daytime)
     if $cust_main->payby eq 'LECB' && ! $cust_main->payinfo;
 
+  if ( grep length($packet->{$_}), FS::cust_main->location_fields ) {
+    my $bill_hash;
+    foreach my $f (FS::cust_main->location_fields) {
+      $bill_hash->{$f} =  $packet->{$f};
+    }
+    my $bill_location = FS::cust_location->new($bill_hash);
+    $cust_main->set('bill_location' => $bill_location);
+    $cust_main->set('ship_location' => $bill_location);
+  }
+
   my @invoicing_list = $packet->{'invoicing_list'}
                          ? split( /\s*\,\s*/, $packet->{'invoicing_list'} )
                          : ();
 
+  my %insert_options = ();
+
+  my @exempt_groups = grep /\S/, $conf->config('tax-cust_exempt-groups');
+  my @tax_exempt = grep { $packet->{"tax_$_"} eq 'Y' } @exempt_groups;
+  $insert_options{'tax_exemption'} = {
+    map { $_ => $packet->{"tax_$_".'_num'} } @tax_exempt
+  };
+
   $packet->{'pkgpart'} =~ /^(\d+)$/ or '' =~ /^()$/;
   my $pkgpart = $1;
   return { 'error' => 'Please select a package' } unless $pkgpart; #msgcat
@@ -659,7 +690,7 @@ sub new_customer {
     my $svc = new FS::svc_acct {
       'svcpart'   => $svcpart,
       map { $_ => $packet->{$_} }
-        qw( username _password sec_phrase popnum ),
+        qw( username _password sec_phrase popnum domsvc ),
     };
 
     my @acct_snarf;
@@ -742,6 +773,7 @@ sub new_customer {
     \%hash,
     \@invoicing_list,
     'depend_jobnum' => $placeholder->jobnum,
+     %insert_options,
   );
   if ( $error ) {
     my $perror = $placeholder->delete;
@@ -762,13 +794,15 @@ sub new_customer {
     #     " new customer: $bill_error"
     #  if $bill_error;
 
-    $bill_error = $cust_main->realtime_collect(
-       method        => FS::payby->payby2bop( $packet->{payby} ),
-       depend_jobnum => $placeholder->jobnum,
-       selfservice   => 1,
-    );
-    #warn "$me error collecting from new customer: $bill_error"
-    #  if $bill_error;
+    unless ( $packet->{payby} eq 'PREPAY' ) {
+      $bill_error = $cust_main->realtime_collect(
+         method        => FS::payby->payby2bop( $packet->{payby} ),
+         depend_jobnum => $placeholder->jobnum,
+         selfservice   => 1,
+      );
+      #warn "$me error collecting from new customer: $bill_error"
+      #  if $bill_error;
+    }
 
     if ($bill_error && ref($bill_error) eq 'HASH') {
       return { 'error' => '_collect',
@@ -933,15 +967,27 @@ sub capture_payment {
   }
 
   my $cust_main = $cust_pay_pending->cust_main;
-  my $bill_error =
-    $cust_main->realtime_botpp_capture( $cust_pay_pending, 
-      %{$packet->{data}},
-      apply => 1,
-  );
+  if ( $packet->{cancel} ) {
+    # the user has chosen not to make this payment
+    # (probably should be a separate API call, but I don't want to duplicate
+    # all of the above...which should eventually go away)
+    my $error = $cust_pay_pending->delete;
+    # don't show any errors related to this; they're not meaningful
+    warn "error canceling pending payment $paypendingnum: $error\n" if $error;
+    return { 'error'      => '_cancel',
+             'session_id' => $cust_pay_pending->session_id };
+  } else {
+    # create the payment
+    my $bill_error =
+      $cust_main->realtime_botpp_capture( $cust_pay_pending, 
+        %{$packet->{data}},
+        apply => 1,
+    );
 
-  return { 'error'      => ( $bill_error->{bill_error} ? '_decline' : '' ),
-           %$bill_error,
-         };
+    return { 'error'      => ( $bill_error->{bill_error} ? '_decline' : '' ),
+             %$bill_error,
+           };
+  }
 
 }