agent-virtualize credit card surcharge percentage, RT#72961
[freeside.git] / FS / FS / contact.pm
index e5ddcdc..fd3e9d7 100644 (file)
@@ -90,10 +90,6 @@ empty or bcrypt
 
 disabled
 
 
 disabled
 
-=item invoice_dest
-
-empty, or 'Y' if email invoices should be sent to this contact
-
 =back
 
 =head1 METHODS
 =back
 
 =head1 METHODS
@@ -116,10 +112,10 @@ sub table { 'contact'; }
 Adds this record to the database.  If there is an error, returns the error,
 otherwise returns false.
 
 Adds this record to the database.  If there is an error, returns the error,
 otherwise returns false.
 
-If the object has an C<emailaddress> field, L<FS::contact_email> records will
-be created for each (comma-separated) email address in that field. If any of
-these coincide with an existing email address, this contact will be merged with
-the contact with that address.
+If the object has an C<emailaddress> field, L<FS::contact_email> records
+will be created for each (comma-separated) email address in that field. If
+any of these coincide with an existing email address, this contact will be
+merged with the contact with that address.
 
 Then, if the object has any fields named C<phonetypenumN> an
 L<FS::contact_phone> record will be created for each of them. Those fields
 
 Then, if the object has any fields named C<phonetypenumN> an
 L<FS::contact_phone> record will be created for each of them. Those fields
@@ -134,6 +130,7 @@ be included in that record, if they are set on the object:
 - classnum
 - comment
 - selfservice_access
 - classnum
 - comment
 - selfservice_access
+- invoice_dest
 
 =cut
 
 
 =cut
 
@@ -157,7 +154,7 @@ sub insert {
   $self->custnum('');
 
   my %link_hash = ();
   $self->custnum('');
 
   my %link_hash = ();
-  for (qw( classnum comment selfservice_access )) {
+  for (qw( classnum comment selfservice_access invoice_dest )) {
     $link_hash{$_} = $self->get($_);
     $self->$_('');
   }
     $link_hash{$_} = $self->get($_);
     $self->$_('');
   }
@@ -209,6 +206,10 @@ sub insert {
   }
 
   my $cust_contact = '';
   }
 
   my $cust_contact = '';
+  # if $self->custnum was set, then the customer-specific properties
+  # (custnum, classnum, invoice_dest, selfservice_access, comment) are in
+  # pseudo-fields, and are now in %link_hash. otherwise, ignore all those
+  # fields.
   if ( $custnum ) {
     my %hash = ( 'contactnum' => $self->contactnum,
                  'custnum'    => $custnum,
   if ( $custnum ) {
     my %hash = ( 'contactnum' => $self->contactnum,
                  'custnum'    => $custnum,
@@ -340,6 +341,8 @@ sub delete {
     }
   }
 
     }
   }
 
+  # if $self->custnum was set, then we're removing the contact from this
+  # customer.
   if ( $self->custnum ) {
     my $cust_contact = qsearchs('cust_contact', {
                          'contactnum'  => $self->contactnum,
   if ( $self->custnum ) {
     my $cust_contact = qsearchs('cust_contact', {
                          'contactnum'  => $self->contactnum,
@@ -381,7 +384,8 @@ sub delete {
     }
   }
 
     }
   }
 
-  my $error = $self->SUPER::delete;
+  my $error = $self->delete_password_history
+           || $self->SUPER::delete;
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
     return $error;
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
     return $error;
@@ -425,7 +429,7 @@ sub replace {
   $self->custnum('');
 
   my %link_hash = ();
   $self->custnum('');
 
   my %link_hash = ();
-  for (qw( classnum comment selfservice_access )) {
+  for (qw( classnum comment selfservice_access invoice_dest )) {
     $link_hash{$_} = $self->get($_);
     $self->$_('');
   }
     $link_hash{$_} = $self->get($_);
     $self->$_('');
   }
@@ -440,6 +444,10 @@ sub replace {
   }
 
   my $cust_contact = '';
   }
 
   my $cust_contact = '';
+  # if $self->custnum was set, then the customer-specific properties
+  # (custnum, classnum, invoice_dest, selfservice_access, comment) are in
+  # pseudo-fields, and are now in %link_hash. otherwise, ignore all those
+  # fields.
   if ( $custnum ) {
     my %hash = ( 'contactnum' => $self->contactnum,
                  'custnum'    => $custnum,
   if ( $custnum ) {
     my %hash = ( 'contactnum' => $self->contactnum,
                  'custnum'    => $custnum,
@@ -674,7 +682,6 @@ sub check {
     || $self->ut_textn('_password')
     || $self->ut_enum('_password_encoding', [ '', 'bcrypt'])
     || $self->ut_enum('disabled', [ '', 'Y' ])
     || $self->ut_textn('_password')
     || $self->ut_enum('_password_encoding', [ '', 'bcrypt'])
     || $self->ut_enum('disabled', [ '', 'Y' ])
-    || $self->ut_flag('invoice_dest')
   ;
   return $error if $error;
 
   ;
   return $error if $error;
 
@@ -746,9 +753,9 @@ sub firstlast {
 
 =item by_selfservice_email EMAILADDRESS
 
 
 =item by_selfservice_email EMAILADDRESS
 
-Alternate search constructor (class method).  Given an email address,
-returns the contact for that address, or the empty string if no contact
-has that email address.
+Alternate search constructor (class method).  Given an email address, returns
+the contact for that address. If that contact doesn't have selfservice access,
+or there isn't one, returns the empty string.
 
 =cut
 
 
 =cut
 
@@ -759,7 +766,8 @@ sub by_selfservice_email {
     'table'     => 'contact_email',
     'addl_from' => ' LEFT JOIN contact USING ( contactnum ) ',
     'hashref'   => { 'emailaddress' => $email, },
     'table'     => 'contact_email',
     'addl_from' => ' LEFT JOIN contact USING ( contactnum ) ',
     'hashref'   => { 'emailaddress' => $email, },
-    'extra_sql' => " AND ( disabled IS NULL OR disabled = '' )",
+    'extra_sql' => " AND ( contact.disabled IS NULL ) ".
+                   " AND ( contact.selfservice_access = 'Y' )",
   }) or return '';
 
   $contact_email->contact;
   }) or return '';
 
   $contact_email->contact;
@@ -880,9 +888,9 @@ sub send_reset_email {
   my $agentnum = $cust_main ? $cust_main->agentnum : '';
   my $msgnum = $conf->config('selfservice-password_reset_msgnum', $agentnum);
   #die "selfservice-password_reset_msgnum unset" unless $msgnum;
   my $agentnum = $cust_main ? $cust_main->agentnum : '';
   my $msgnum = $conf->config('selfservice-password_reset_msgnum', $agentnum);
   #die "selfservice-password_reset_msgnum unset" unless $msgnum;
-  return { 'error' => "selfservice-password_reset_msgnum unset" } unless $msgnum;
+  return "selfservice-password_reset_msgnum unset" unless $msgnum;
   my $msg_template = qsearchs('msg_template', { msgnum => $msgnum } );
   my $msg_template = qsearchs('msg_template', { msgnum => $msgnum } );
-  return { 'error' => "selfservice-password_reset_msgnum cannot be loaded" } unless $msg_template;
+  return "selfservice-password_reset_msgnum cannot be loaded" unless $msg_template;
   my %msg_template = (
     'to'            => join(',', map $_->emailaddress, @contact_email ),
     'cust_main'     => $cust_main,
   my %msg_template = (
     'to'            => join(',', map $_->emailaddress, @contact_email ),
     'cust_main'     => $cust_main,
@@ -894,7 +902,7 @@ sub send_reset_email {
 
     my $cust_msg = $msg_template->prepare( %msg_template );
     my $error = $cust_msg->insert;
 
     my $cust_msg = $msg_template->prepare( %msg_template );
     my $error = $cust_msg->insert;
-    return { 'error' => $error } if $error;
+    return $error if $error;
     my $queue = new FS::queue {
       'job'     => 'FS::cust_msg::process_send',
       'custnum' => $cust_main ? $cust_main->custnum : '',
     my $queue = new FS::queue {
       'job'     => 'FS::cust_msg::process_send',
       'custnum' => $cust_main ? $cust_main->custnum : '',
@@ -945,9 +953,24 @@ use FS::upgrade_journal;
 sub _upgrade_data { #class method
   my ($class, %opts) = @_;
 
 sub _upgrade_data { #class method
   my ($class, %opts) = @_;
 
+  # before anything else, migrate contact.custnum to cust_contact records
+  unless ( FS::upgrade_journal->is_done('contact_invoice_dest') ) {
+
+    local($skip_fuzzyfiles) = 1;
+
+    foreach my $contact (qsearch('contact', {})) {
+      my $error = $contact->replace;
+      die $error if $error;
+    }
+
+    FS::upgrade_journal->set_done('contact_invoice_dest');
+  }
+
+
   # always migrate cust_main_invoice records over
   local $FS::cust_main::import = 1; # override require_phone and such
   my $search = FS::Cursor->new('cust_main_invoice', {});
   # always migrate cust_main_invoice records over
   local $FS::cust_main::import = 1; # override require_phone and such
   my $search = FS::Cursor->new('cust_main_invoice', {});
+  my %custnum_dest;
   while (my $cust_main_invoice = $search->fetch) {
     my $custnum = $cust_main_invoice->custnum;
     my $dest = $cust_main_invoice->dest;
   while (my $cust_main_invoice = $search->fetch) {
     my $custnum = $cust_main_invoice->custnum;
     my $dest = $cust_main_invoice->dest;
@@ -959,26 +982,21 @@ sub _upgrade_data { #class method
         if !$svc_acct;
       $dest = $svc_acct->email;
     }
         if !$svc_acct;
       $dest = $svc_acct->email;
     }
+    push @{ $custnum_dest{$custnum} ||= [] }, $dest;
 
 
-    my $error = $cust_main->replace( [ $dest ] );
-
+    my $error = $cust_main_invoice->delete;
     if ( $error ) {
     if ( $error ) {
-      die "custnum $custnum, invoice destination $dest, creating contact: $error\n";
+      die "custnum $custnum, cleaning up cust_main_invoice: $error\n";
     }
     }
+  }
 
 
-    $error = $cust_main_invoice->delete;
-    die "custnum $custnum, cleaning up cust_main_invoice: $error\n" if $error;
-
-  } # while $search->fetch
-
-  unless ( FS::upgrade_journal->is_done('contact__DUPEMAIL') ) {
-
-    foreach my $contact (qsearch('contact', {})) {
-      my $error = $contact->replace;
-      die $error if $error;
+  foreach my $custnum (keys %custnum_dest) {
+    my $dests = $custnum_dest{$custnum};
+    my $cust_main = FS::cust_main->by_key($custnum);
+    my $error = $cust_main->replace( invoicing_list => $dests );
+    if ( $error ) {
+      die "custnum $custnum, creating contact: $error\n";
     }
     }
-
-    FS::upgrade_journal->set_done('contact__DUPEMAIL');
   }
 
 }
   }
 
 }