handle BIGSERIAL like SERIAL for the cdr table, and normalize canadian zip codes...
[freeside.git] / FS / FS / Record.pm
index d843658..a7af708 100644 (file)
@@ -250,7 +250,7 @@ sub qsearch {
   my $table = $cache ? $cache->table : $stable;
   my $dbdef_table = dbdef->table($table)
     or die "No schema for table $table found - ".
-           "do you need to create it or run dbdef-create?";
+           "do you need to run freeside-upgrade?";
   my $pkey = $dbdef_table->primary_key;
 
   my @real_fields = grep exists($record->{$_}), real_fields($table);
@@ -285,7 +285,7 @@ sub qsearch {
         if ( $op eq '=' ) {
           if ( driver_name eq 'Pg' ) {
             my $type = dbdef->table($table)->column($column)->type;
-            if ( $type =~ /(int|serial)/i ) {
+            if ( $type =~ /(int|(big)?serial)/i ) {
               qq-( $column IS NULL )-;
             } else {
               qq-( $column IS NULL OR $column = '' )-;
@@ -296,7 +296,7 @@ sub qsearch {
         } elsif ( $op eq '!=' ) {
           if ( driver_name eq 'Pg' ) {
             my $type = dbdef->table($table)->column($column)->type;
-            if ( $type =~ /(int|serial)/i ) {
+            if ( $type =~ /(int|(big)?serial)/i ) {
               qq-( $column IS NOT NULL )-;
             } else {
               qq-( $column IS NOT NULL AND $column != '' )-;
@@ -365,7 +365,7 @@ sub qsearch {
     grep defined( $record->{$_} ) && $record->{$_} ne '', @real_fields
   ) {
     if ( $record->{$field} =~ /^\d+(\.\d+)?$/
-         && dbdef->table($table)->column($field)->type =~ /(int|serial)/i
+         && dbdef->table($table)->column($field)->type =~ /(int|(big)?serial)/i
     ) {
       $sth->bind_param($bind++, $record->{$field}, { TYPE => SQL_INTEGER } );
     } else {
@@ -433,7 +433,8 @@ sub qsearch {
         } values(%result);
       }
     } else {
-      warn "untested code (class FS::$table uses custom new method)";
+      #okay, its been tested
+      # warn "untested code (class FS::$table uses custom new method)";
       @return = map {
         eval 'FS::'. $table. '->new( { %{$_} } )';
       } values(%result);
@@ -694,7 +695,7 @@ sub insert {
     my $col = $self->dbdef_table->column($primary_key);
     
     $db_seq =
-      uc($col->type) eq 'SERIAL'
+      uc($col->type) =~ /^(BIG)?SERIAL\d?/
       || ( driver_name eq 'Pg'
              && defined($col->default)
              && $col->default =~ /^nextval\(/i
@@ -744,18 +745,32 @@ sub insert {
 
   $sth->execute or return $sth->errstr;
 
-  my $insertid = '';
-  if ( $db_seq ) { # get inserted id from the database, if applicable
+  # get inserted id from the database, if applicable & needed
+  if ( $db_seq && ! $self->getfield($primary_key) ) {
     warn "[debug]$me retreiving sequence from database\n" if $DEBUG;
+  
+    my $insertid = '';
+
     if ( driver_name eq 'Pg' ) {
 
-      my $oid = $sth->{'pg_oid_status'};
-      my $i_sql = "SELECT $primary_key FROM $table WHERE oid = ?";
+      #my $oid = $sth->{'pg_oid_status'};
+      #my $i_sql = "SELECT $primary_key FROM $table WHERE oid = ?";
+
+      my $default = $self->dbdef_table->column($primary_key)->default;
+      unless ( $default =~ /^nextval\('"?([\w\.]+)"?'/i ) {
+        dbh->rollback if $FS::UID::AutoCommit;
+        return "can't parse $table.$primary_key default value".
+               " for sequence name: $default";
+      }
+      my $sequence = $1;
+
+      my $i_sql = "SELECT currval('$sequence')";
       my $i_sth = dbh->prepare($i_sql) or do {
         dbh->rollback if $FS::UID::AutoCommit;
         return dbh->errstr;
       };
-      $i_sth->execute($oid) or do {
+      #$i_sth->execute($oid) or do {
+      $i_sth->execute() or do {
         dbh->rollback if $FS::UID::AutoCommit;
         return $i_sth->errstr;
       };
@@ -781,11 +796,15 @@ sub insert {
       }
 
     } else {
+
       dbh->rollback if $FS::UID::AutoCommit;
       return "don't know how to retreive inserted ids from ". driver_name. 
              ", try using counterfiles (maybe run dbdef-create?)";
+
     }
+
     $self->setfield($primary_key, $insertid);
+
   }
 
   my @virtual_fields = 
@@ -958,6 +977,11 @@ sub replace {
 
   warn "[debug]$me $new ->replace $old\n" if $DEBUG;
 
+  if ( $new->can('replace_check') ) {
+    my $error = $new->replace_check($old);
+    return $error if $error;
+  }
+
   return "Records not in same table!" unless $new->table eq $old->table;
 
   my $primary_key = $old->dbdef_table->primary_key;
@@ -1002,7 +1026,7 @@ sub replace {
          #false laziness w/qsearch
          if ( driver_name eq 'Pg' ) {
             my $type = $old->dbdef_table->column($_)->type;
-            if ( $type =~ /(int|serial)/i ) {
+            if ( $type =~ /(int|(big)?serial)/i ) {
               qq-( $_ IS NULL )-;
             } else {
               qq-( $_ IS NULL OR $_ = '' )-;
@@ -1470,22 +1494,40 @@ Check/untaint zip codes.
 
 =cut
 
+my @zip_reqd_countries = qw( CA ); #US implicit...
+
 sub ut_zip {
   my( $self, $field, $country ) = @_;
+
   if ( $country eq 'US' ) {
-    $self->getfield($field) =~ /\s*(\d{5}(\-\d{4})?)\s*$/
+
+    $self->getfield($field) =~ /^\s*(\d{5}(\-\d{4})?)\s*$/
+      or return gettext('illegal_zip'). " $field for country $country: ".
+                $self->getfield($field);
+    $self->setfield($field, $1);
+
+  } elsif ( $country eq 'CA' ) {
+
+    $self->getfield($field) =~ /^\s*([A-Z]\d[A-Z])\s*(\d[A-Z]\d)\s*$/i
       or return gettext('illegal_zip'). " $field for country $country: ".
                 $self->getfield($field);
-    $self->setfield($field,$1);
+    $self->setfield($field, "$1 $2");
+
   } else {
-    if ( $self->getfield($field) =~ /^\s*$/ ) {
+
+    if ( $self->getfield($field) =~ /^\s*$/
+         && ( !$country || ! grep { $_ eq $country } @zip_reqd_countries )
+       )
+    {
       $self->setfield($field,'');
     } else {
       $self->getfield($field) =~ /^\s*(\w[\w\-\s]{2,8}\w)\s*$/
         or return gettext('illegal_zip'). " $field: ". $self->getfield($field);
       $self->setfield($field,$1);
     }
+
   }
+
   '';
 }