unique checking for svc_phone like svc_acct, closes: RT#4204 (also a few lines of...
[freeside.git] / FS / FS / svc_Common.pm
index 787acee..2866bfe 100644 (file)
@@ -3,6 +3,7 @@ package FS::svc_Common;
 use strict;
 use vars qw( @ISA $noexport_hack $DEBUG $me );
 use Carp qw( cluck carp croak ); #specify cluck have to specify them all..
+use Scalar::Util qw( blessed );
 use FS::Record qw( qsearch qsearchs fields dbh );
 use FS::cust_main_Mixin;
 use FS::cust_svc;
@@ -40,13 +41,15 @@ inherit from, i.e. FS::svc_acct.  FS::svc_Common inherits from FS::Record.
 
 Class method which returns an SQL fragment to search for STRING in FIELD.
 
+It is now case-insensitive by default.
+
 =cut
 
 sub search_sql_field {
   my( $class, $field, $string ) = @_;
   my $table = $class->table;
   my $q_string = dbh->quote($string);
-  "$table.$field = $q_string";
+  "LOWER($table.$field) = LOWER($q_string)";
 }
 
 #fallback for services that don't provide a search... 
@@ -206,7 +209,6 @@ sub insert {
   my $objects = $options{'child_objects'} || [];
   my $depend_jobnums = $options{'depend_jobnum'} || [];
   $depend_jobnums = [ $depend_jobnums ] unless ref($depend_jobnums);
-  my $error;
 
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
@@ -219,9 +221,6 @@ sub insert {
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
 
-  $error = $self->check;
-  return $error if $error;
-
   my $svcnum = $self->svcnum;
   my $cust_svc = $svcnum ? qsearchs('cust_svc',{'svcnum'=>$self->svcnum}) : '';
   #unless ( $svcnum ) {
@@ -232,7 +231,7 @@ sub insert {
       'pkgnum'  => $self->pkgnum,
       'svcpart' => $self->svcpart,
     } );
-    $error = $cust_svc->insert;
+    my $error = $cust_svc->insert;
     if ( $error ) {
       $dbh->rollback if $oldAutoCommit;
       return $error;
@@ -248,13 +247,10 @@ sub insert {
     $self->svcpart($cust_svc->svcpart);
   }
 
-  $error = $self->set_auto_inventory;
-  if ( $error ) {
-    $dbh->rollback if $oldAutoCommit;
-    return $error;
-  }
-
-  $error = $self->SUPER::insert;
+  my $error =    $self->set_auto_inventory
+              || $self->check
+              || $self->_check_duplicate
+              || $self->SUPER::insert;
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
     return $error;
@@ -319,6 +315,10 @@ sub insert {
   '';
 }
 
+#fallbacks
+sub _check_duplcate { ''; }
+sub table_dupcheck_fields { (); }
+
 =item delete [ , OPTION => VALUE ... ]
 
 Deletes this account from the database.  If there is an error, returns the
@@ -359,7 +359,7 @@ sub delete {
   '';
 }
 
-=item replace OLD_RECORD
+=item replace [ OLD_RECORD ] [ HASHREF | OPTION => VALUE ]
 
 Replaces OLD_RECORD with this one.  If there is an error, returns the error,
 otherwise returns false.
@@ -367,8 +367,16 @@ otherwise returns false.
 =cut
 
 sub replace {
-  my ($new, $old) = (shift, shift);
-  my %options = @_;
+  my $new = shift;
+
+  my $old = ( blessed($_[0]) && $_[0]->isa('FS::Record') )
+              ? shift
+              : $new->replace_old;
+
+  my $options = 
+    ( ref($_[0]) eq 'HASH' )
+      ? shift
+      : { @_ };
 
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
@@ -381,15 +389,31 @@ sub replace {
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
 
-  # We absolutely have to have an old vs. new record to make this work.
-  $old = $new->replace_old unless defined($old);
-
   my $error = $new->set_auto_inventory;
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
     return $error;
   }
 
+  #redundant, but so any duplicate fields are maniuplated as appropriate
+  # (svc_phone.phonenum)
+  my $error = $new->check;
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
+
+  #if ( $old->username ne $new->username || $old->domsvc != $new->domsvc ) {
+  if ( grep { $old->$_ ne $new->$_ } $new->table_dupcheck_fields ) {
+
+    $new->svcpart( $new->cust_svc->svcpart ) unless $new->svcpart;
+    $error = $new->_check_duplicate;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
   $error = $new->SUPER::replace($old);
   if ($error) {
     $dbh->rollback if $oldAutoCommit;
@@ -399,7 +423,7 @@ sub replace {
   #new-style exports!
   unless ( $noexport_hack ) {
 
-    my $export_args = $options{'export_args'} || [];
+    my $export_args = $options->{'export_args'} || [];
 
     #not quite false laziness, but same pattern as FS::svc_acct::replace and
     #FS::part_export::sqlradius::_export_replace.  List::Compare or something
@@ -511,7 +535,7 @@ sub setx {
   return $error if $error;
 
   my $part_svc = $self->part_svc;
-  return "Unkonwn svcpart" unless $part_svc;
+  return "Unknown svcpart" unless $part_svc;
 
   #set default/fixed/whatever fields from part_svc
 
@@ -708,6 +732,19 @@ sub unsuspend {
   $self->export('unsuspend', @$export_args);
 }
 
+=item export_links
+
+Runs export_links callbacks and returns the links.
+
+=cut
+
+sub export_links {
+  my $self = shift;
+  my $return = [];
+  $self->export('links', $return);
+  $return;
+}
+
 =item export HOOK [ EXPORT_ARGS ]
 
 Runs the provided export hook (i.e. "suspend", "unsuspend") for this service.