[freeside-commits] freeside/FS/FS svc_phone.pm, 1.15, 1.16 svc_acct.pm, 1.247, 1.248 Record.pm, 1.172, 1.173 msgcat.pm, 1.6, 1.7 Setup.pm, 1.14, 1.15 Conf.pm, 1.255, 1.256 svc_Common.pm, 1.47, 1.48

Ivan,,, ivan at wavetail.420.am
Sun Dec 21 13:33:30 PST 2008


Update of /home/cvs/cvsroot/freeside/FS/FS
In directory wavetail.420.am:/tmp/cvs-serv7874/FS/FS

Modified Files:
	svc_phone.pm svc_acct.pm Record.pm msgcat.pm Setup.pm Conf.pm 
	svc_Common.pm 
Log Message:
unique checking for svc_phone like svc_acct, closes: RT#4204 (also a few lines of the new per-agent config snuck in Conf.pm from RT#3989)

Index: Conf.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/Conf.pm,v
retrieving revision 1.255
retrieving revision 1.256
diff -u -d -r1.255 -r1.256
--- Conf.pm	1 Dec 2008 07:52:24 -0000	1.255
+++ Conf.pm	21 Dec 2008 21:33:28 -0000	1.256
@@ -97,7 +97,7 @@
   $hashref->{agentnum} = $agentnum;
   local $FS::Record::conf = undef;  # XXX evil hack prevents recursion
   my $cv = FS::Record::qsearchs('conf', $hashref);
-  if (!$cv && defined($agentnum)) {
+  if (!$cv && defined($agentnum) && $agentnum) {
     $hashref->{agentnum} = '';
     $cv = FS::Record::qsearchs('conf', $hashref);
   }
@@ -763,6 +763,7 @@
     'section'     => 'required',
     'description' => 'Return address on email invoices',
     'type'        => 'text',
+    'per_agent'   => 1,
   },
 
   {
@@ -1701,6 +1702,14 @@
   },
 
   {
+    'key'         => 'global_unique-phonenum',
+    'section'     => '',
+    'description' => 'Global phone number uniqueness control: none (usual setting - check countrycode+phonenumun uniqueness per exports), or countrycode+phonenum (all countrycode+phonenum pairs are globally unique, regardless of exports).  disabled turns off duplicate checking completely and is STRONGLY NOT RECOMMENDED unless you REALLY need to turn this off.',
+    'type'        => 'select',
+    'select_enum' => [ 'none', 'countrycode+phonenum', 'disabled' ],
+  },
+
+  {
     'key'         => 'svc_external-skip_manual',
     'section'     => 'UI',
     'description' => 'When provisioning svc_external services, skip manual entry of id and title fields in the UI.  Usually used in conjunction with an export that populates these fields (i.e. artera_turbo).',
@@ -1799,6 +1808,7 @@
     'section'     => 'required',
     'description' => 'Your company name',
     'type'        => 'text',
+    'per_agent'   => 1,
   },
 
   {
@@ -1806,6 +1816,7 @@
     'section'     => 'required',
     'description' => 'Your company address',
     'type'        => 'textarea',
+    'per_agent'   => 1,
   },
 
   {

Index: svc_phone.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/svc_phone.pm,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- svc_phone.pm	29 Nov 2008 21:54:35 -0000	1.15
+++ svc_phone.pm	21 Dec 2008 21:33:27 -0000	1.16
@@ -1,16 +1,22 @@
 package FS::svc_phone;
 
 use strict;
-use vars qw( @ISA @pw_set );
+use vars qw( @ISA @pw_set $conf );
 use FS::Conf;
-#use FS::Record qw( qsearch qsearchs );
+use FS::Record qw( qsearch qsearchs );
 use FS::svc_Common;
+use FS::part_svc;
 
 @ISA = qw( FS::svc_Common );
 
 #avoid l 1 and o O 0
 @pw_set = ( 'a'..'k', 'm','n', 'p-z', 'A'..'N', 'P'..'Z' , '2'..'9' );
 
+#ask FS::UID to run this stuff for us later
+$FS::UID::callback{'FS::svc_acct'} = sub { 
+  $conf = new FS::Conf;
+};
+
 =head1 NAME
 
 FS::svc_phone - Object methods for svc_phone records
@@ -102,6 +108,8 @@
 
 sub table { 'svc_phone'; }
 
+sub table_dupcheck_fields { ( 'countrycode', 'phonenum' ); }
+
 =item search_sql STRING
 
 Class method which returns an SQL fragment to search for the given string.
@@ -215,6 +223,67 @@
   $self->SUPER::check;
 }
 
+=item _check duplicate
+
+Internal method to check for duplicate phone numers.
+
+=cut
+
+#false laziness w/svc_acct.pm's _check_duplicate.
+sub _check_duplicate {
+  my $self = shift;
+
+  my $global_unique = $conf->config('global_unique-phonenum') || 'none';
+  return '' if $global_unique eq 'disabled';
+
+  $self->lock_table;
+
+  my @dup_ccphonenum =
+    grep { !$self->svcnum || $_->svcnum != $self->svcnum }
+    qsearch( 'svc_phone', {
+      'countrycode' => $self->countrycode,
+      'phonenum'    => $self->phonenum,
+    });
+
+  return gettext('phonenum_in_use')
+    if $global_unique eq 'countrycode+phonenum' && @dup_ccphonenum;
+
+  my $part_svc = qsearchs('part_svc', { 'svcpart' => $self->svcpart } );
+  unless ( $part_svc ) {
+    return 'unknown svcpart '. $self->svcpart;
+  }
+
+  if ( @dup_ccphonenum ) {
+
+    my $exports = FS::part_export::export_info('svc_phone');
+    my %conflict_ccphonenum_svcpart = ( $self->svcpart => 'SELF', );
+
+    foreach my $part_export ( $part_svc->part_export ) {
+
+      #this will catch to the same exact export
+      my @svcparts = map { $_->svcpart } $part_export->export_svc;
+
+      $conflict_ccphonenum_svcpart{$_} = $part_export->exportnum
+        foreach @svcparts;
+
+    }
+
+    foreach my $dup_ccphonenum ( @dup_ccphonenum ) {
+      my $dup_svcpart = $dup_ccphonenum->cust_svc->svcpart;
+      if ( exists($conflict_ccphonenum_svcpart{$dup_svcpart}) ) {
+        return "duplicate phone number ".
+               $self->countrycode. ' '. $self->phonenum.
+               ": conflicts with svcnum ". $dup_ccphonenum->svcnum.
+               " via exportnum ". $conflict_ccphonenum_svcpart{$dup_svcpart};
+      }
+    }
+
+  }
+
+  return '';
+
+}
+
 =item check_pin
 
 Checks the supplied PIN against the PIN in the database.  Returns true for a

Index: svc_acct.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/svc_acct.pm,v
retrieving revision 1.247
retrieving revision 1.248
diff -u -d -r1.247 -r1.248
--- svc_acct.pm	6 Nov 2008 04:22:59 -0000	1.247
+++ svc_acct.pm	21 Dec 2008 21:33:28 -0000	1.248
@@ -337,6 +337,8 @@
 
 sub table { 'svc_acct'; }
 
+sub table_dupcheck_fields { ( 'username', 'domsvc' ); }
+
 sub _fieldhandlers {
   {
     #false laziness with edit/svc_acct.cgi
@@ -499,12 +501,6 @@
     $self->svcpart($cust_svc->svcpart);
   }
 
-  $error = $self->_check_duplicate;
-  if ( $error ) {
-    $dbh->rollback if $oldAutoCommit;
-    return $error;
-  }
-
   my @jobnums;
   $error = $self->SUPER::insert(
     'jobnums'       => \@jobnums,
@@ -817,15 +813,6 @@
 
   }
 
-  if ( $old->username ne $new->username || $old->domsvc != $new->domsvc ) {
-    $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;
@@ -1227,7 +1214,7 @@
 
 =item _check_duplicate
 
-Internal function to check for duplicates usernames, username at domain pairs and
+Internal method to check for duplicates usernames, username at domain pairs and
 uids.
 
 If the I<global_unique-username> configuration value is set to B<username> or
@@ -1244,20 +1231,7 @@
   my $global_unique = $conf->config('global_unique-username') || 'none';
   return '' if $global_unique eq 'disabled';
 
-  warn "$me locking svc_acct table for duplicate search" if $DEBUG;
-  if ( driver_name =~ /^Pg/i ) {
-    dbh->do("LOCK TABLE svc_acct IN SHARE ROW EXCLUSIVE MODE")
-      or die dbh->errstr;
-  } elsif ( driver_name =~ /^mysql/i ) {
-    dbh->do("SELECT * FROM duplicate_lock
-               WHERE lockname = 'svc_acct'
-	       FOR UPDATE"
-	   ) or die dbh->errstr;
-  } else {
-    die "unknown database ". driver_name.
-        "; don't know how to lock for duplicate search";
-  }
-  warn "$me acquired svc_acct table lock for duplicate search" if $DEBUG;
+  $self->lock_table;
 
   my $part_svc = qsearchs('part_svc', { 'svcpart' => $self->svcpart } );
   unless ( $part_svc ) {

Index: Setup.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/Setup.pm,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- Setup.pm	23 Aug 2008 21:59:43 -0000	1.14
+++ Setup.pm	21 Dec 2008 21:33:28 -0000	1.15
@@ -461,6 +461,10 @@
       'en_US' => 'Username in use',
     },
 
+    'phonenum_in_use' => {
+      'en_US' => 'Phone number in use',
+    },
+
     'illegal_email_invoice_address' => {
       'en_US' => 'Illegal email invoice address',
     },

Index: msgcat.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/msgcat.pm,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- msgcat.pm	18 Jun 2008 00:36:51 -0000	1.6
+++ msgcat.pm	21 Dec 2008 21:33:28 -0000	1.7
@@ -4,7 +4,7 @@
 use vars qw( @ISA );
 use Exporter;
 use FS::UID;
-use FS::Record;
+use FS::Record qw( qsearchs );
 
 @ISA = qw(FS::Record);
 
@@ -117,6 +117,38 @@
   $self->SUPER::check
 }
 
+
+sub _upgrade_data { #class method
+  my( $class, %opts) = @_;
+
+  eval "use FS::Setup;";
+  die $@ if $@;
+
+  #"repopulate_msgcat", false laziness w/FS::Setup::populate_msgcat
+
+  my %messages = FS::Setup::msgcat_messages();
+
+  foreach my $msgcode ( keys %messages ) {
+    foreach my $locale ( keys %{$messages{$msgcode}} ) {
+      my %msgcat = (
+        'msgcode' => $msgcode,
+        'locale'  => $locale,
+        #'msg'     => $messages{$msgcode}{$locale},
+      );
+      my $msgcat = qsearchs('msgcat', \%msgcat);
+      next if $msgcat;
+
+      $msgcat = new FS::msgcat( {
+        %msgcat,
+        'msg' => $messages{$msgcode}{$locale},
+      } );
+      my $error = $msgcat->insert;
+      die $error if $error;
+    }
+  }
+
+}
+
 =back
 
 =head1 BUGS

Index: Record.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/Record.pm,v
retrieving revision 1.172
retrieving revision 1.173
diff -u -d -r1.172 -r1.173
--- Record.pm	9 Dec 2008 01:49:55 -0000	1.172
+++ Record.pm	21 Dec 2008 21:33:28 -0000	1.173
@@ -766,6 +766,50 @@
   } );
 }
 
+=item lock_table
+
+Locks this table with a database-driver specific lock method.  This is used
+as a mutex in order to do a duplicate search.
+
+For PostgreSQL, does "LOCK TABLE tablename IN SHARE ROW EXCLUSIVE MODE".
+
+For MySQL, does a SELECT FOR UPDATE on the duplicate_lock table.
+
+Errors are fatal; no useful return value.
+
+Note: To use this method for new tables other than svc_acct and svc_phone,
+edit freeside-upgrade and add those tables to the duplicate_lock list.
+
+=cut
+
+sub lock_table {
+  my $self = shift;
+  my $table = $self->table;
+
+  warn "$me locking $table table\n" if $DEBUG;
+
+  if ( driver_name =~ /^Pg/i ) {
+
+    dbh->do("LOCK TABLE $table IN SHARE ROW EXCLUSIVE MODE")
+      or die dbh->errstr;
+
+  } elsif ( driver_name =~ /^mysql/i ) {
+
+    dbh->do("SELECT * FROM duplicate_lock
+               WHERE lockname = '$table'
+	       FOR UPDATE"
+	   ) or die dbh->errstr;
+
+  } else {
+
+    die "unknown database ". driver_name. "; don't know how to lock table";
+
+  }
+
+  warn "$me acquired $table table lock\n" if $DEBUG;
+
+}
+
 =item insert
 
 Inserts this record to the database.  If there is an error, returns the error,

Index: svc_Common.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/svc_Common.pm,v
retrieving revision 1.47
retrieving revision 1.48
diff -u -d -r1.47 -r1.48
--- svc_Common.pm	14 Aug 2008 01:52:28 -0000	1.47
+++ svc_Common.pm	21 Dec 2008 21:33:28 -0000	1.48
@@ -249,6 +249,7 @@
 
   my $error =    $self->set_auto_inventory
               || $self->check
+              || $self->_check_duplicate
               || $self->SUPER::insert;
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
@@ -314,6 +315,10 @@
   '';
 }
 
+#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
@@ -390,6 +395,25 @@
     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;



More information about the freeside-commits mailing list