add dsl, circuit and fiber services to email and RT ticket exports, RT#84345
[freeside.git] / FS / FS / contact.pm
index 7e474f1..761f751 100644 (file)
@@ -1,5 +1,6 @@
 package FS::contact;
-use base qw( FS::Record );
+use base qw( FS::Password_Mixin
+             FS::Record );
 
 use strict;
 use vars qw( $skip_fuzzyfiles );
@@ -11,6 +12,7 @@ use FS::contact_class;
 use FS::cust_location;
 use FS::contact_phone;
 use FS::contact_email;
+use FS::contact::Import;
 use FS::queue;
 use FS::cust_pkg;
 use FS::phone_type; #for cgi_contact_fields
@@ -129,6 +131,7 @@ sub insert {
   my $dbh = dbh;
 
   my $error = $self->SUPER::insert;
+
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
     return $error;
@@ -179,7 +182,7 @@ sub insert {
     }
   }
 
-  if ( $self->selfservice_access ) {
+  if ( $self->selfservice_access && ! length($self->_password) ) {
     my $error = $self->send_reset_email( queue=>1 );
     if ( $error ) {
       $dbh->rollback if $oldAutoCommit;
@@ -187,6 +190,15 @@ sub insert {
     }
   }
 
+  if ( $self->get('password') ) {
+    my $error = $self->is_password_allowed($self->get('password'))
+          ||  $self->change_password($self->get('password'));
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
 
   '';
@@ -230,7 +242,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;
@@ -268,6 +281,9 @@ sub replace {
   my $dbh = dbh;
 
   my $error = $self->SUPER::replace($old);
+  if ( $old->_password ne $self->_password ) {
+    $error ||= $self->insert_password_history;
+  }
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
     return $error;
@@ -283,8 +299,11 @@ sub replace {
              );
     my $contact_phone = qsearchs('contact_phone', \%cp);
 
-    # if new value is empty, delete old entry
-    if (!$self->get($pf)) {
+    my $pv = $self->get($pf);
+       $pv =~ s/\s//g;
+
+    #if new value is empty, delete old entry
+    if (!$pv) {
       if ($contact_phone) {
         $error = $contact_phone->delete;
         if ( $error ) {
@@ -297,7 +316,7 @@ sub replace {
 
     $contact_phone ||= new FS::contact_phone \%cp;
 
-    my %cpd = _parse_phonestring( $self->get($pf) );
+    my %cpd = _parse_phonestring( $pv );
     $contact_phone->set( $_ => $cpd{$_} ) foreach keys %cpd;
 
     my $method = $contact_phone->contactphonenum ? 'replace' : 'insert';
@@ -360,6 +379,15 @@ sub replace {
     }
   }
 
+  if ( $self->get('password') ) {
+    my $error = $self->is_password_allowed($self->get('password'))
+          ||  $self->change_password($self->get('password'));
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
 
   '';
@@ -446,7 +474,7 @@ and replace methods.
 sub check {
   my $self = shift;
 
-  if ( $self->selfservice_access eq 'R' ) {
+  if ( $self->selfservice_access eq 'R' || $self->selfservice_access eq 'E' || $self->selfservice_access eq 'P' ) {
     $self->selfservice_access('Y');
     $self->_resend('Y');
   }
@@ -558,7 +586,33 @@ has that email address.
 =cut
 
 sub by_selfservice_email {
-  my($class, $email) = @_;
+  my($class, $email, $case_insensitive) = @_;
+
+  my $email_search = "emailaddress = '".$email."'";
+  $email_search = "LOWER(emailaddress) = LOWER('".$email."')" if $case_insensitive;
+
+  my $contact_email = qsearchs({
+    'table'     => 'contact_email',
+    'addl_from' => ' LEFT JOIN contact USING ( contactnum ) ',
+    'extra_sql' => " WHERE $email_search".
+                   " AND selfservice_access = 'Y' ".
+                   " AND ( disabled IS NULL OR disabled = '' )",
+  }) or return '';
+
+  $contact_email->contact;
+
+}
+
+=item by_selfservice_email_custnum EMAILADDRESS, CUSTNUM
+
+Alternate search constructor (class method).  Given an email address and custnum, returns
+the contact for that address and custnum. If that contact doesn't have selfservice access,
+or there isn't one, returns the empty string.
+
+=cut
+
+sub by_selfservice_email_custnum {
+  my($class, $email, $custnum) = @_;
 
   my $contact_email = qsearchs({
     'table'     => 'contact_email',
@@ -594,7 +648,7 @@ sub authenticate_password {
 
     $hash eq $check_hash;
 
-  } else { 
+  } else {
 
     return 0 if $self->_password eq '';
 
@@ -604,9 +658,22 @@ sub authenticate_password {
 
 }
 
+=item change_password NEW_PASSWORD
+
+Changes the contact's selfservice access password to NEW_PASSWORD. This does
+not check password policy rules (see C<is_password_allowed>) and will return
+an error only if editing the record fails for some reason.
+
+If NEW_PASSWORD is the same as the existing password, this does nothing.
+
+=cut
+
 sub change_password {
   my($self, $new_password) = @_;
 
+  # do nothing if the password is unchanged
+  return if $self->authenticate_password($new_password);
+
   $self->change_password_fields( $new_password );
 
   $self->replace;
@@ -652,7 +719,10 @@ sub send_reset_email {
     'svcnum'     => $opt{'svcnum'},
   };
 
-  my $timeout = '24 hours'; #?
+  
+  my $conf = new FS::Conf;
+  my $timeout =
+    ($conf->config('selfservice-password_reset_hours') || 24 ). ' hours';
 
   my $reset_session_id;
   do {
@@ -664,8 +734,6 @@ sub send_reset_email {
 
   #email it
 
-  my $conf = new FS::Conf;
-
   my $cust_main = $self->cust_main
     or die "no customer"; #reset a password for a prospect contact?  someday
 
@@ -718,6 +786,7 @@ sub cgi_contact_fields {
 
   my @contact_fields = qw(
     classnum first last title comment emailaddress selfservice_access
+    invoice_dest password
   );
 
   push @contact_fields, 'phonetypenum'. $_->phonetypenum