RT# 76722 - added option to search on tags not selected in advanced customer report
[freeside.git] / FS / FS / cust_main / Search.pm
index ef106b5..58bdd88 100644 (file)
@@ -161,20 +161,23 @@ sub smart_search {
 
   # custnum search (also try agent_custid), with some tweaking options if your
   # legacy cust "numbers" have letters
-  } elsif ( $search =~ /^\s*(\d+)\s*$/
-         || ( $conf->config('cust_main-agent_custid-format') eq 'ww?d+'
-              && $search =~ /^\s*(\w\w?\d+)\s*$/
-            )
-         || ( $conf->config('cust_main-custnum-display_special')
-           # it's not currently possible for special prefixes to contain
-           # digits, so just strip off any alphabetic prefix and match 
-           # the rest to custnum
-              && $search =~ /^\s*[[:alpha:]]*(\d+)\s*$/
-            )
-         || ( $conf->exists('address1-search' )
-              && $search =~ /^\s*(\d+\-?\w*)\s*$/ #i.e. 1234A or 9432-D
-            )
-     )
+  } elsif (    $search =~ /^\s*(\d+)\s*$/
+            or ( $conf->config('cust_main-agent_custid-format') eq 'ww?d+'
+                 && $search =~ /^\s*(\w\w?\d+)\s*$/
+               )
+            or ( $conf->config('cust_main-agent_custid-format') eq 'd+-w'
+                 && $search =~ /^\s*(\d+-\w)\s*$/
+               )
+            or ( $conf->config('cust_main-custnum-display_special')
+                 # it's not currently possible for special prefixes to contain
+                 # digits, so just strip off any alphabetic prefix and match 
+                 # the rest to custnum
+                 && $search =~ /^\s*[[:alpha:]]*(\d+)\s*$/
+               )
+            or ( $conf->exists('address1-search' )
+                 && $search =~ /^\s*(\d+\-?\w*)\s*$/ #i.e. 1234A or 9432-D
+               )
+          )
   {
 
     my $num = $1;
@@ -218,6 +221,7 @@ sub smart_search {
       # probably the Right Thing: return customers that have any associated
       # locations matching the string, not just bill/ship location
       push @cust_main, qsearch( {
+        'select'    => 'cust_main.*',
         'table'     => 'cust_main',
         'addl_from' => ' JOIN cust_location USING (custnum) ',
         'hashref'   => { %options, },
@@ -356,10 +360,14 @@ sub smart_search {
 
       #still some false laziness w/search (was search/cust_main.cgi)
 
+      my $min_len =
+        $FS::CurrentUser::CurrentUser->access_right('List all customers')
+        ? 3 : 4;
+
       #substring
 
       my @company_hashrefs = ();
-      if ( length($value) >= 3 ) {
+      if ( length($value) >= $min_len ) {
         @company_hashrefs = (
           { 'company'      => { op=>'ILIKE', value=>"%$value%" }, },
           { 'ship_company' => { op=>'ILIKE', value=>"%$value%" }, },
@@ -375,7 +383,7 @@ sub smart_search {
           },
         );
 
-      } elsif ( length($value) >= 3 ) {
+      } elsif ( length($value) >= $min_len ) {
 
         @hashrefs = (
           { 'first'        => { op=>'ILIKE', value=>"%$value%" }, },
@@ -396,9 +404,10 @@ sub smart_search {
 
       }
 
-      if ( $conf->exists('address1-search') && length($value) >= 3 ) {
+      if ( $conf->exists('address1-search') && length($value) >= $min_len ) {
 
         push @cust_main, qsearch( {
+          select    => 'cust_main.*',
           table     => 'cust_main',
           addl_from => 'JOIN cust_location USING (custnum)',
           extra_sql => 'WHERE '.
@@ -444,7 +453,8 @@ sub smart_search {
             'contact.first'  => $first }, #
           %fuzopts
         );
-     }
+      }
+
       foreach my $field ( 'first', 'last', 'company', 'ship_company' ) {
         push @cust_main, FS::cust_main::Search->fuzzy_search(
           { $field => $value },
@@ -877,6 +887,29 @@ sub search {
     if $params->{'no_tax'};
 
   ##
+  # with referrals
+  ##
+  if ( $params->{with_referrals} =~ /^\s*(\d+)\s*$/ ) {
+
+    my $n = $1;
+  
+    # referral status
+    my $and_status = '';
+    if ( grep { $params->{referral_status} eq $_ } FS::cust_main->statuses() ) {
+      my $method = $params->{referral_status}. '_sql';
+      $and_status = ' AND '. FS::cust_main->$method();
+      $and_status =~ s/ cust_main\./ referred_cust_main./g;
+    }
+
+    push @where,
+      " $n <= ( SELECT COUNT(*) FROM cust_main AS referred_cust_main
+                  WHERE cust_main.custnum = referred_cust_main.referral_custnum
+                    $and_status
+              )";
+
+  }
+
+  ##
   # dates
   ##
 
@@ -1016,8 +1049,9 @@ sub search {
 
     if ( @tagnums ) {
       if ( $params->{'all_tags'} ) {
+        my $exists = $params->{'all_tags'} eq 'all' ? 'exists' : 'not exists';
         foreach ( @tagnums ) {
-          push @where, 'exists(select 1 from cust_tag where '.
+          push @where, $exists.'(select 1 from cust_tag where '.
                        'cust_tag.custnum = cust_main.custnum and tagnum = '.
                        $_ . ')';
         }
@@ -1096,8 +1130,9 @@ sub search {
                  FS::UI::Web::cust_sql_fields($params->{'cust_fields'}),
                );
 
-  my(@extra_headers) = ();
-  my(@extra_fields)  = ();
+  my @extra_headers     = ();
+  my @extra_fields      = ();
+  my @extra_sort_fields = ();
 
   if ($params->{'flattened_pkgs'}) {
 
@@ -1142,22 +1177,39 @@ sub search {
                                          my $p = $a[!.--$headercount. q!];
                                          $p;
                                         };!;
+      unshift @extra_sort_fields, '';
     }
 
   }
 
+  if ( $params->{'with_referrals'} ) {
+
+    #XXX next: num for each customer status
+     
+    push @select,
+      '( SELECT COUNT(*) FROM cust_main AS referred_cust_main
+           WHERE cust_main.custnum = referred_cust_main.referral_custnum
+       ) AS num_referrals';
+
+    unshift @extra_headers, 'Referrals';
+    unshift @extra_fields, 'num_referrals';
+    unshift @extra_sort_fields, 'num_referrals';
+
+  }
+
   my $select = join(', ', @select);
 
   my $sql_query = {
-    'table'         => 'cust_main',
-    'select'        => $select,
-    'addl_from'     => $addl_from,
-    'hashref'       => {},
-    'extra_sql'     => $extra_sql,
-    'order_by'      => $orderby,
-    'count_query'   => $count_query,
-    'extra_headers' => \@extra_headers,
-    'extra_fields'  => \@extra_fields,
+    'table'             => 'cust_main',
+    'select'            => $select,
+    'addl_from'         => $addl_from,
+    'hashref'           => {},
+    'extra_sql'         => $extra_sql,
+    'order_by'          => $orderby,
+    'count_query'       => $count_query,
+    'extra_headers'     => \@extra_headers,
+    'extra_fields'      => \@extra_fields,
+    'extra_sort_fields' => \@extra_sort_fields,
   };
   #warn Data::Dumper::Dumper($sql_query);
   $sql_query;