import customer from Excel file too
[freeside.git] / FS / FS / Record.pm
index d82924a..2540dd3 100644 (file)
@@ -3,9 +3,12 @@ package FS::Record;
 use strict;
 use vars qw( $AUTOLOAD @ISA @EXPORT_OK $DEBUG
              $conf $me
-             %virtual_fields_cache $nowarn_identical $no_update_diff );
+             %virtual_fields_cache
+             $nowarn_identical $no_update_diff $no_check_foreign
+           );
 use Exporter;
 use Carp qw(carp cluck croak confess);
+use Scalar::Util qw( blessed );
 use File::CounterFile;
 use Locale::Country;
 use DBI qw(:sql_types);
@@ -24,13 +27,15 @@ use Tie::IxHash;
 @ISA = qw(Exporter);
 
 #export dbdef for now... everything else expects to find it here
-@EXPORT_OK = qw(dbh fields hfields qsearch qsearchs dbdef jsearch str2time_sql);
+@EXPORT_OK = qw(dbh fields hfields qsearch qsearchs dbdef jsearch
+                str2time_sql str2time_sql_closing );
 
 $DEBUG = 0;
 $me = '[FS::Record]';
 
 $nowarn_identical = 0;
 $no_update_diff = 0;
+$no_check_foreign = 0;
 
 my $rsa_module;
 my $rsa_loaded;
@@ -40,7 +45,7 @@ my $rsa_decrypt;
 FS::UID->install_callback( sub {
   eval "use FS::Conf;";
   die $@ if $@;
-  $conf = new FS::Conf
+  $conf = FS::Conf->new
   $File::CounterFile::DEFAULT_DIR = $conf->base_dir . "/counters.". datasrc;
 } );
 
@@ -236,6 +241,8 @@ fine in the common case where there are only two parameters:
 
 =cut
 
+my %TYPE = (); #for debugging
+
 sub qsearch {
   my($stable, $record, $select, $extra_sql, $order_by, $cache, $addl_from );
   my $debug = '';
@@ -296,21 +303,33 @@ sub qsearch {
   foreach my $field (
     grep defined( $record->{$_} ) && $record->{$_} ne '', @real_fields
   ) {
-    if ( $record->{$field} =~ /^\d+(\.\d+)?$/
-         && dbdef->table($table)->column($field)->type =~ /(int|(big)?serial)/i
-    ) {
-      $sth->bind_param($bind++, $record->{$field}, { TYPE => SQL_INTEGER } );
-    }elsif ( $record->{$field} =~ /^[+-]?\d+(\.\d+)?$/
-         && dbdef->table($table)->column($field)->type =~ /(numeric)/i
-    ) {
-      $sth->bind_param($bind++, $record->{$field}, { TYPE => SQL_FLOAT } );
-    }elsif ( $record->{$field} =~ /[-+]?\d*\.?\d+([eE][-+]?\d+)?/
-         && dbdef->table($table)->column($field)->type =~ /(float4)/i
-    ) {
-      $sth->bind_param($bind++, $record->{$field}, { TYPE => SQL_FLOAT } );
-    } else {
-      $sth->bind_param($bind++, $record->{$field}, { TYPE => SQL_VARCHAR } );
+
+    my $value = $record->{$field};
+    $value = $value->{'value'} if ref($value);
+    my $type = dbdef->table($table)->column($field)->type;
+
+    my $TYPE = SQL_VARCHAR;
+    if ( $type =~ /(int|(big)?serial)/i && $value =~ /^\d+(\.\d+)?$/ ) {
+      $TYPE = SQL_INTEGER;
+
+    #DBD::Pg 1.49: Cannot bind ... unknown sql_type 6
+    #} elsif (    ( $type =~ /(numeric)/i     && $value =~ /^[+-]?\d+(\.\d+)?$/)
+    #          || ( $type =~ /(real|float4)/i
+    #                 && $value =~ /[-+]?\d*\.?\d+([eE][-+]?\d+)?/
+    #             )
+    #        ) {
+    #  $TYPE = SQL_FLOAT;
+    }
+
+    if ( $DEBUG > 2 ) {
+      no strict 'refs';
+      %TYPE = map { &{"DBI::$_"}() => $_ } @{ $DBI::EXPORT_TAGS{sql_types} }
+        unless keys %TYPE;
+      warn "  bind_param $bind (for field $field), $value, TYPE $TYPE{$TYPE}\n";
     }
+
+    $sth->bind_param($bind++, $value, { TYPE => $TYPE } );
+
   }
 
 #  $sth->execute( map $record->{$_},
@@ -664,11 +683,11 @@ sub AUTOLOAD {
   $field =~ s/.*://;
   if ( defined($value) ) {
     confess "errant AUTOLOAD $field for $self (arg $value)"
-      unless ref($self) && $self->can('setfield');
+      unless blessed($self) && $self->can('setfield');
     $self->setfield($field,$value);
   } else {
     confess "errant AUTOLOAD $field for $self (no args)"
-      unless ref($self) && $self->can('getfield');
+      unless blessed($self) && $self->can('getfield');
     $self->getfield($field);
   }    
 }
@@ -787,17 +806,18 @@ sub insert {
   }
 
   my $table = $self->table;
-
   
   # Encrypt before the database
-  if ($conf->exists('encryption') && defined(eval '@FS::'. $table . '::encrypted_fields')) {
+  if (    defined(eval '@FS::'. $table . '::encrypted_fields')
+       && scalar( eval '@FS::'. $table . '::encrypted_fields')
+       && $conf->exists('encryption')
+  ) {
     foreach my $field (eval '@FS::'. $table . '::encrypted_fields') {
       $self->{'saved'} = $self->getfield($field);
       $self->setfield($field, $self->encrypt($self->getfield($field)));
     }
   }
 
-
   #false laziness w/delete
   my @real_fields =
     grep { defined($self->getfield($_)) && $self->getfield($_) ne "" }
@@ -1286,7 +1306,7 @@ sub _h_statement {
 
   # If we're encrypting then don't ever store the payinfo or CVV2 in the history....
   # You can see if it changed by the paymask...
-  if ($conf->exists('encryption') ) {
+  if ($conf && $conf->exists('encryption') ) {
     @fields = grep  $_ ne 'payinfo' && $_ ne 'cvv2', @fields;
   }
   my @values = map { _quote( $self->getfield($_), $self->table, $_) } @fields;
@@ -1594,6 +1614,8 @@ sub ut_phonen {
     $self->setfield($field,'');
   } elsif ( $country eq 'US' || $country eq 'CA' ) {
     $phonen =~ s/\D//g;
+    $phonen = $conf->config('cust_main-default_areacode').$phonen
+      if length($phonen)==7 && $conf->config('cust_main-default_areacode');
     $phonen =~ /^(\d{3})(\d{3})(\d{4})(\d*)$/
       or return gettext('illegal_phone'). " $field: ". $self->getfield($field);
     $phonen = "$1-$2-$3";
@@ -1886,6 +1908,7 @@ on the column first.
 
 sub ut_foreign_key {
   my( $self, $field, $table, $foreign ) = @_;
+  return '' if $no_check_foreign;
   qsearchs($table, { $foreign => $self->getfield($field) })
     or return "Can't find ". $self->table. ".$field ". $self->getfield($field).
               " in $table.$foreign";