sprinkle some magic ajax fairy dust on referring customer SELEKTAH. rewind! make...
authorivan <ivan>
Mon, 14 Aug 2006 12:13:40 +0000 (12:13 +0000)
committerivan <ivan>
Mon, 14 Aug 2006 12:13:40 +0000 (12:13 +0000)
12 files changed:
FS/FS/cust_main.pm
httemplate/edit/cust_main.cgi
httemplate/elements/header.html
httemplate/elements/search-cust_main.html [new file with mode: 0644]
rt/html/Elements/FreesideInvoiceSearch [new file with mode: 0644]
rt/html/Elements/FreesideNewCust
rt/html/Elements/FreesideSearch
rt/html/Elements/FreesideSvcSearch
rt/html/Elements/PageLayout
rt/html/Elements/SimpleSearch
rt/html/Elements/Tabs
rt/html/NoAuth/webrt.css

index 3f67c62..7962f6d 100644 (file)
@@ -3824,8 +3824,8 @@ sub uncancel_sql { "
 =item fuzzy_search FUZZY_HASHREF [ HASHREF, SELECT, EXTRA_SQL, CACHE_OBJ ]
 
 Performs a fuzzy (approximate) search and returns the matching FS::cust_main
 =item fuzzy_search FUZZY_HASHREF [ HASHREF, SELECT, EXTRA_SQL, CACHE_OBJ ]
 
 Performs a fuzzy (approximate) search and returns the matching FS::cust_main
-records.  Currently, only I<last> or I<company> may be specified (the
-appropriate ship_ field is also searched if applicable).
+records.  Currently, I<first>, I<last> and/or I<company> may be specified (the
+appropriate ship_ field is also searched).
 
 Additional options are the same as FS::Record::qsearch
 
 
 Additional options are the same as FS::Record::qsearch
 
@@ -3839,19 +3839,25 @@ sub fuzzy_search {
 
   check_and_rebuild_fuzzyfiles();
   foreach my $field ( keys %$fuzzy ) {
 
   check_and_rebuild_fuzzyfiles();
   foreach my $field ( keys %$fuzzy ) {
-    my $sub = \&{"all_$field"};
     my %match = ();
     my %match = ();
-    $match{$_}=1 foreach ( amatch($fuzzy->{$field}, ['i'], @{ &$sub() } ) );
+    $match{$_}=1 foreach ( amatch( $fuzzy->{$field},
+                                   ['i'],
+                                   @{ $self->all_X($field) }
+                                 )
+                         );
 
 
+    my @fcust = ();
     foreach ( keys %match ) {
     foreach ( keys %match ) {
-      push @cust_main, qsearch('cust_main', { %$hash, $field=>$_}, @opt);
-      push @cust_main, qsearch('cust_main', { %$hash, "ship_$field"=>$_}, @opt)
-        if defined dbdef->table('cust_main')->column('ship_last');
+      push @fcust, qsearch('cust_main', { %$hash, $field=>$_}, @opt);
+      push @fcust, qsearch('cust_main', { %$hash, "ship_$field"=>$_}, @opt);
     }
     }
+    my %fsaw = ();
+    push @cust_main, grep { ! $fsaw{$_->custnum}++ } @fcust;
   }
 
   }
 
+  # we want the components of $fuzzy ANDed, not ORed, but still don't want dupes
   my %saw = ();
   my %saw = ();
-  @cust_main = grep { !$saw{$_->custnum}++ } @cust_main;
+  @cust_main = grep { ++$saw{$_->custnum} == scalar(keys %$fuzzy) } @cust_main;
 
   @cust_main;
 
 
   @cust_main;
 
@@ -3866,8 +3872,9 @@ sub fuzzy_search {
 =item smart_search OPTION => VALUE ...
 
 Accepts the following options: I<search>, the string to search for.  The string
 =item smart_search OPTION => VALUE ...
 
 Accepts the following options: I<search>, the string to search for.  The string
-will be searched for as a customer number, last name or company name, first
-searching for an exact match then fuzzy and substring matches.
+will be searched for as a customer number, phone number, name or company name,
+first searching for an exact match then fuzzy and substring matches (in some
+cases - see the source code for the exact heuristics used).
 
 Any additional options treated as an additional qualifier on the search
 (i.e. I<agentnum>).
 
 Any additional options treated as an additional qualifier on the search
 (i.e. I<agentnum>).
@@ -3878,13 +3885,53 @@ Returns a (possibly empty) array of FS::cust_main objects.
 
 sub smart_search {
   my %options = @_;
 
 sub smart_search {
   my %options = @_;
-  my $search = delete $options{'search'};
 
   #here is the agent virtualization
   my $agentnums_sql = $FS::CurrentUser::CurrentUser->agentnums_sql;
 
   my @cust_main = ();
 
   #here is the agent virtualization
   my $agentnums_sql = $FS::CurrentUser::CurrentUser->agentnums_sql;
 
   my @cust_main = ();
-  if ( $search =~ /^\s*(\d+)\s*$/ ) { # customer # search
+
+  my $search = delete $options{'search'};
+  ( my $alphanum_search = $search ) =~ s/\W//g;
+  
+  if ( $alphanum_search =~ /^1?(\d{3})(\d{3})(\d{4})(\d*)$/ ) { #phone# search
+
+    #false laziness w/Record::ut_phone
+    my $phonen = "$1-$2-$3";
+    $phonen .= " x$4" if $4;
+
+    push @cust_main, qsearch( {
+      'table'   => 'cust_main',
+      'hashref' => { %options },
+      'extra_sql' => ( scalar(keys %options) ? ' AND ' : ' WHERE ' ).
+                     ' ( '.
+                         join(' OR ', map "$_ = '$phonen'",
+                                          qw( daytime night fax
+                                              ship_daytime ship_night ship_fax )
+                             ).
+                     ' ) '.
+                     " AND $agentnums_sql", #agent virtualization
+    } );
+
+    unless ( @cust_main || $phonen =~ /x\d+$/ ) { #no exact match
+      #try looking for matches with extensions unless one was specified
+
+      push @cust_main, qsearch( {
+        'table'   => 'cust_main',
+        'hashref' => { %options },
+        'extra_sql' => ( scalar(keys %options) ? ' AND ' : ' WHERE ' ).
+                       ' ( '.
+                           join(' OR ', map "$_ LIKE '$phonen\%'",
+                                            qw( daytime night
+                                                ship_daytime ship_night )
+                               ).
+                       ' ) '.
+                       " AND $agentnums_sql", #agent virtualization
+      } );
+
+    }
+
+  } elsif ( $search =~ /^\s*(\d+)\s*$/ ) { # customer # search
 
     push @cust_main, qsearch( {
       'table'     => 'cust_main',
 
     push @cust_main, qsearch( {
       'table'     => 'cust_main',
@@ -3892,22 +3939,86 @@ sub smart_search {
       'extra_sql' => " AND $agentnums_sql", #agent virtualization
     } );
 
       'extra_sql' => " AND $agentnums_sql", #agent virtualization
     } );
 
-  } elsif ( $search =~ /^\s*(\S.*\S)\s*$/ ) { #value search
+  } elsif ( $search =~ /^\s*(\S.*\S)\s+\((.+), ([^,]+)\)\s*$/ ) {
+
+    my($company, $last, $first) = ( $1, $2, $3 );
+
+    # "Company (Last, First)"
+    #this is probably something a browser remembered,
+    #so just do an exact search
+
+    foreach my $prefix ( '', 'ship_' ) {
+      push @cust_main, qsearch( {
+        'table'     => 'cust_main',
+        'hashref'   => { $prefix.'first'   => $first,
+                         $prefix.'last'    => $last,
+                         $prefix.'company' => $company,
+                         %options,
+                       },
+        'extra_sql' => " AND $agentnums_sql",
+      } );
+    }
+
+  } elsif ( $search =~ /^\s*(\S.*\S)\s*$/ ) { # value search
+                                              # try (ship_){last,company}
 
     my $value = lc($1);
 
 
     my $value = lc($1);
 
-    # remove "(Last, First)" in "Company (Last, First"), otherwise the
-    # full strings the browser remembers won't work
-    $value =~ s/\([\w \,\.\-\']*\)$//; #false laziness w/Record::ut_name
+    # # remove "(Last, First)" in "Company (Last, First)", otherwise the
+    # # full strings the browser remembers won't work
+    # $value =~ s/\([\w \,\.\-\']*\)$//; #false laziness w/Record::ut_name
+
+    use Lingua::EN::NameParse;
+    my $NameParse = new Lingua::EN::NameParse(
+             auto_clean     => 1,
+             allow_reversed => 1,
+    );
+
+    my($last, $first) = ( '', '' );
+    #maybe disable this too and just rely on NameParse?
+    if ( $value =~ /^(.+),\s*([^,]+)$/ ) { # Last, First
     
     
+      ($last, $first) = ( $1, $2 );
+    
+    #} elsif  ( $value =~ /^(.+)\s+(.+)$/ ) {
+    } elsif ( ! $NameParse->parse($value) ) {
+
+      my %name = $NameParse->components;
+      $first = $name{'given_name_1'};
+      $last  = $name{'surname_1'};
+
+    }
+
+    if ( $first && $last ) {
+
+      my($q_last, $q_first) = ( dbh->quote($last), dbh->quote($first) );
+
+      #exact
+      my $sql = scalar(keys %options) ? ' AND ' : ' WHERE ';
+      $sql .= "
+        (     ( LOWER(last) = $q_last AND LOWER(first) = $q_first )
+           OR ( LOWER(ship_last) = $q_last AND LOWER(ship_first) = $q_first )
+        )";
+
+      push @cust_main, qsearch( {
+        'table'     => 'cust_main',
+        'hashref'   => \%options,
+        'extra_sql' => "$sql AND $agentnums_sql", #agent virtualization
+      } );
+
+      # or it just be something that was typed in... (try that in a sec)
+
+    }
+
     my $q_value = dbh->quote($value);
 
     #exact
     my $sql = scalar(keys %options) ? ' AND ' : ' WHERE ';
     my $q_value = dbh->quote($value);
 
     #exact
     my $sql = scalar(keys %options) ? ' AND ' : ' WHERE ';
-    $sql .= " ( LOWER(last) = $q_value OR LOWER(company) = $q_value";
-    $sql .= " OR LOWER(ship_last) = $q_value OR LOWER(ship_company) = $q_value"
-      if defined dbdef->table('cust_main')->column('ship_last');
-    $sql .= ' )';
+    $sql .= " (    LOWER(last)         = $q_value
+                OR LOWER(company)      = $q_value
+                OR LOWER(ship_last)    = $q_value
+                OR LOWER(ship_company) = $q_value
+              )";
 
     push @cust_main, qsearch( {
       'table'     => 'cust_main',
 
     push @cust_main, qsearch( {
       'table'     => 'cust_main',
@@ -3920,56 +4031,62 @@ sub smart_search {
       #still some false laziness w/ search/cust_main.cgi
 
       #substring
       #still some false laziness w/ search/cust_main.cgi
 
       #substring
-      push @cust_main, qsearch( {
-        'table'     => 'cust_main',
-        'hashref'   => { 'last'     => { 'op'    => 'ILIKE',
-                                         'value' => "%$value%" },
-                         %options,
-                       },
-        'extra_sql' => " AND $agentnums_sql", #agent virtualizaiton
-      } );
-      push @cust_main, qsearch( {
-        'table'     => 'cust_main',
-        'hashref'   => { 'ship_last' => { 'op'     => 'ILIKE',
-                                          'value' => "%$value%" },
-                         %options, 
-                       },
-        'extra_sql' => " AND $agentnums_sql", #agent virtualization
-      } )
-        if defined dbdef->table('cust_main')->column('ship_last');
 
 
-      push @cust_main, qsearch( {
-        'table'     => 'cust_main',
-        'hashref'   => { 'company'  => { 'op'    => 'ILIKE',
-                                         'value' => "%$value%" },
-                         %options,
-                       },
-        'extra_sql' => " AND $agentnums_sql", #agent virtualization
-      } );
-      push @cust_main, qsearch(  {
-        'table'     => 'cust_main',
-        'hashref'   => { 'ship_company' => { 'op'    => 'ILIKE',
-                                             'value' => "%$value%" },
-                         %options,
-                       },
-        'extra_sql' => " AND $agentnums_sql", #agent virtualization
-      } )
-        if defined dbdef->table('cust_main')->column('ship_last');
+      my @hashrefs = (
+        { 'company'      => { op=>'ILIKE', value=>"%$value%" }, },
+        { 'ship_company' => { op=>'ILIKE', value=>"%$value%" }, },
+      );
+
+      if ( $first && $last ) {
+
+        push @hashrefs,
+          { 'first'        => { op=>'ILIKE', value=>"%$first%" },
+            'last'         => { op=>'ILIKE', value=>"%$last%" },
+          },
+          { 'ship_first'   => { op=>'ILIKE', value=>"%$first%" },
+            'ship_last'    => { op=>'ILIKE', value=>"%$last%" },
+          },
+        ;
+
+      } else {
+
+        push @hashrefs,
+          { 'last'         => { op=>'ILIKE', value=>"%$value%" }, },
+          { 'ship_last'    => { op=>'ILIKE', value=>"%$value%" }, },
+        ;
+      }
+
+      foreach my $hashref ( @hashrefs ) {
+
+        push @cust_main, qsearch( {
+          'table'     => 'cust_main',
+          'hashref'   => { %$hashref,
+                           %options,
+                         },
+          'extra_sql' => " AND $agentnums_sql", #agent virtualizaiton
+        } );
+
+      }
 
       #fuzzy
 
       #fuzzy
-      push @cust_main, FS::cust_main->fuzzy_search(
-        { 'last'     => $value }, #fuzzy hashref
-        \%options,                #hashref
-        '',                       #select
-        " AND $agentnums_sql",    #extra_sql  #agent virtualization
-      );
-      push @cust_main, FS::cust_main->fuzzy_search(
-        { 'company'  => $value }, #fuzzy hashref
+      my @fuzopts = (
         \%options,                #hashref
         '',                       #select
         " AND $agentnums_sql",    #extra_sql  #agent virtualization
       );
 
         \%options,                #hashref
         '',                       #select
         " AND $agentnums_sql",    #extra_sql  #agent virtualization
       );
 
+      if ( $first && $last ) {
+        push @cust_main, FS::cust_main->fuzzy_search(
+          { 'last'   => $last,    #fuzzy hashref
+            'first'  => $first }, #
+          @fuzopts
+        );
+      }
+      foreach my $field ( 'last', 'company' ) {
+        push @cust_main,
+          FS::cust_main->fuzzy_search( { $field => $value }, @fuzopts );
+      }
+
     }
 
     #eliminate duplicates
     }
 
     #eliminate duplicates
@@ -3986,10 +4103,12 @@ sub smart_search {
 
 =cut
 
 
 =cut
 
+use vars qw(@fuzzyfields);
+@fuzzyfields = ( 'last', 'first', 'company' );
+
 sub check_and_rebuild_fuzzyfiles {
   my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
 sub check_and_rebuild_fuzzyfiles {
   my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
-  -e "$dir/cust_main.last" && -e "$dir/cust_main.company"
-    or &rebuild_fuzzyfiles;
+  rebuild_fuzzyfiles() if grep { ! -e "$dir/cust_main.$_" } @fuzzyfields
 }
 
 =item rebuild_fuzzyfiles
 }
 
 =item rebuild_fuzzyfiles
@@ -4003,71 +4122,39 @@ sub rebuild_fuzzyfiles {
   my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
   mkdir $dir, 0700 unless -d $dir;
 
   my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
   mkdir $dir, 0700 unless -d $dir;
 
-  #last
-
-  open(LASTLOCK,">>$dir/cust_main.last")
-    or die "can't open $dir/cust_main.last: $!";
-  flock(LASTLOCK,LOCK_EX)
-    or die "can't lock $dir/cust_main.last: $!";
-
-  my @all_last = map $_->getfield('last'), qsearch('cust_main', {});
-  push @all_last,
-                 grep $_, map $_->getfield('ship_last'), qsearch('cust_main',{})
-    if defined dbdef->table('cust_main')->column('ship_last');
-
-  open (LASTCACHE,">$dir/cust_main.last.tmp")
-    or die "can't open $dir/cust_main.last.tmp: $!";
-  print LASTCACHE join("\n", @all_last), "\n";
-  close LASTCACHE or die "can't close $dir/cust_main.last.tmp: $!";
-
-  rename "$dir/cust_main.last.tmp", "$dir/cust_main.last";
-  close LASTLOCK;
-
-  #company
-
-  open(COMPANYLOCK,">>$dir/cust_main.company")
-    or die "can't open $dir/cust_main.company: $!";
-  flock(COMPANYLOCK,LOCK_EX)
-    or die "can't lock $dir/cust_main.company: $!";
-
-  my @all_company = grep $_ ne '', map $_->company, qsearch('cust_main',{});
-  push @all_company,
-       grep $_ ne '', map $_->ship_company, qsearch('cust_main', {})
-    if defined dbdef->table('cust_main')->column('ship_last');
+  foreach my $fuzzy ( @fuzzyfields ) {
 
 
-  open (COMPANYCACHE,">$dir/cust_main.company.tmp")
-    or die "can't open $dir/cust_main.company.tmp: $!";
-  print COMPANYCACHE join("\n", @all_company), "\n";
-  close COMPANYCACHE or die "can't close $dir/cust_main.company.tmp: $!";
-
-  rename "$dir/cust_main.company.tmp", "$dir/cust_main.company";
-  close COMPANYLOCK;
-
-}
-
-=item all_last
-
-=cut
+    open(LOCK,">>$dir/cust_main.$fuzzy")
+      or die "can't open $dir/cust_main.$fuzzy: $!";
+    flock(LOCK,LOCK_EX)
+      or die "can't lock $dir/cust_main.$fuzzy: $!";
+  
+    my @all = map $_->getfield($fuzzy), qsearch('cust_main', {});
+    push @all,
+      grep $_, map $_->getfield("ship_$fuzzy"), qsearch('cust_main',{});
+  
+    open (CACHE,">$dir/cust_main.$fuzzy.tmp")
+      or die "can't open $dir/cust_main.$fuzzy.tmp: $!";
+    print CACHE join("\n", @all), "\n";
+    close CACHE or die "can't close $dir/cust_main.$fuzzy.tmp: $!";
+  
+    rename "$dir/cust_main.$fuzzy.tmp", "$dir/cust_main.$fuzzy";
+    close LOCK;
+  }
 
 
-sub all_last {
-  my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
-  open(LASTCACHE,"<$dir/cust_main.last")
-    or die "can't open $dir/cust_main.last: $!";
-  my @array = map { chomp; $_; } <LASTCACHE>;
-  close LASTCACHE;
-  \@array;
 }
 
 }
 
-=item all_company
+=item all_X
 
 =cut
 
 
 =cut
 
-sub all_company {
+sub all_X {
+  my( $self, $field ) = @_;
   my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
   my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
-  open(COMPANYCACHE,"<$dir/cust_main.company")
-    or die "can't open $dir/cust_main.last: $!";
-  my @array = map { chomp; $_; } <COMPANYCACHE>;
-  close COMPANYCACHE;
+  open(CACHE,"<$dir/cust_main.$field")
+    or die "can't open $dir/cust_main.$field: $!";
+  my @array = map { chomp; $_; } <CACHE>;
+  close CACHE;
   \@array;
 }
 
   \@array;
 }
 
index 45cb69f..c3d1804 100755 (executable)
@@ -64,7 +64,9 @@ if ( $cgi->param('error') ) {
   @invoicing_list = ();
 }
 $cgi->delete_all();
   @invoicing_list = ();
 }
 $cgi->delete_all();
+
 my $action = $custnum ? 'Edit' : 'Add';
 my $action = $custnum ? 'Edit' : 'Add';
+$action .= ": ". $cust_main->name if $custnum;
 
 my $r = qq!<font color="#ff0000">*</font>&nbsp;!;
 
 
 my $r = qq!<font color="#ff0000">*</font>&nbsp;!;
 
@@ -139,7 +141,13 @@ if ( $cust_main->referral_custnum
 
   <TR>
     <TD ALIGN="right">Referring customer</TD>
 
   <TR>
     <TD ALIGN="right">Referring customer</TD>
-    <TD><INPUT TYPE="text" NAME="referral_custnum" VALUE=""></TD>
+    <TD>
+      <!-- <INPUT TYPE="text" NAME="referral_custnum" VALUE=""> -->
+      <%= include('/elements/search-cust_main.html',
+                    'field_name' => 'referral_custnum',
+                 )
+      %>
+    </TD>
   </TR>
 
 <% } else { %>
   </TR>
 
 <% } else { %>
index 3aa81be..ea8c418 100644 (file)
@@ -3,6 +3,7 @@
   my $etc = @_ ? shift : ''; #$etc is for things like onLoad= etc.
   my $head = @_ ? shift : ''; #$head is for things that go in the <HEAD> section
   my $conf = new FS::Conf;
   my $etc = @_ ? shift : ''; #$etc is for things like onLoad= etc.
   my $head = @_ ? shift : ''; #$head is for things that go in the <HEAD> section
   my $conf = new FS::Conf;
+
 %>
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML>
 %>
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML>
 
     <SCRIPT TYPE="text/javascript">
       function clearhint_search_cust (what) {
 
     <SCRIPT TYPE="text/javascript">
       function clearhint_search_cust (what) {
-        if ( what.value = '(cust #, name or company)' )
+        if ( what.value == '(cust #, name, company or phone)' )
+          what.value = '';
+      }
+
+      function clearhint_search_invoice (what) {
+        if ( what.value == '(inv #)' )
           what.value = '';
       }
 
       function clearhint_search_svc (what) {
           what.value = '';
       }
 
       function clearhint_search_svc (what) {
-        if ( what.value = '(user, user@domain or domain)' )
+        if ( what.value == '(user, user@domain or domain)' )
           what.value = '';
       }
 
       function clearhint_search_ticket (what) {
           what.value = '';
       }
 
       function clearhint_search_ticket (what) {
-        if ( what.value = '(ticket # or subject string)' )
+        if ( what.value == '(ticket # or subject string)' )
           what.value = '';
       }
     </SCRIPT>
           what.value = '';
       }
     </SCRIPT>
   <BODY BACKGROUND="<%=$fsurl%>images/background-cheat.png" <%= $etc %> STYLE="margin-top:0; margin-bottom:0; margin-left:0; margin-right:0">
     <table width="100%" CELLPADDING=0 CELLSPACING=0 STYLE="padding-left:0; padding-right:4">
       <tr>
   <BODY BACKGROUND="<%=$fsurl%>images/background-cheat.png" <%= $etc %> STYLE="margin-top:0; margin-bottom:0; margin-left:0; margin-right:0">
     <table width="100%" CELLPADDING=0 CELLSPACING=0 STYLE="padding-left:0; padding-right:4">
       <tr>
-        <td rowspan=2 BGCOLOR="#ffffff">
-          <IMG BORDER=0 ALT="freeside" SRC="<%=$fsurl%>images/small-logo.png">
-        </td>
+        <td rowspan=2 BGCOLOR="#ffffff"><IMG BORDER=0 ALT="freeside" SRC="<%=$fsurl%>images/small-logo.png"></td>
         <td align=left rowspan=2 BGCOLOR="#ffffff"> <!-- valign="top" -->
           <font size=6><%= $conf->config('company_name') || 'ExampleCo' %></font>
         </td>
         <td align=left rowspan=2 BGCOLOR="#ffffff"> <!-- valign="top" -->
           <font size=6><%= $conf->config('company_name') || 'ExampleCo' %></font>
         </td>
-        <td align=right valign=top BGCOLOR="#ffffff">Logged in as <b><%= getotaker %>&nbsp</b><br><FONT SIZE="-2"><a href="<%=$fsurl%>pref/XXXwritethis">Preferences</a>&nbsp;<BR><BR></FONT>
+        <td align=right valign=top BGCOLOR="#ffffff"><FONT SIZE="-1">Logged in as <b><%= getotaker %>&nbsp</b><br></FONT><FONT SIZE="-2"><a href="<%=$fsurl%>pref/XXXwritethis">Preferences</a>&nbsp;<BR></FONT>
         </td>
       </tr>
       <tr>
         </td>
       </tr>
       <tr>
       </tr>
     </table>
 
       </tr>
     </table>
 
-    <TABLE WIDTH="100%" CELLSPACING=0 CELLPADDING=4>
+<style type="text/css">
+input.fsblackbutton {
+        background-color:#333333;
+        color: #ffffff;
+        border:1px solid;
+        border-top-color:#cccccc;
+        border-left-color:#cccccc;
+        border-right-color:#aaaaaa;
+        border-bottom-color:#aaaaaa;
+        font-weight:bold;
+        padding-left:12px;
+        padding-right:12px;
+        overflow:visible;
+        filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr='#ff333333',EndColorStr='#ff666666')
+}
+
+input.fsblackbuttonselected {
+        background-color:#7e0079;
+        color: #ffffff;
+        border:1px solid;
+        border-top-color:#cccccc;
+        border-left-color:#cccccc;
+        border-right-color:#aaaaaa;
+        border-bottom-color:#aaaaaa;
+        font-weight:bold;
+        padding-left:12px;
+        padding-right:12px;
+        overflow:visible;
+        filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr='#ff330033',EndColorStr='#ff7e0079')
+}
+</style>
+
+    <TABLE WIDTH="100%" CELLSPACING=0 CELLPADDING=0>
       <TR>
       <TR>
-        <TD COLSPAN=4 WIDTH="100%" STYLE="padding:0"><IMG BORDER=0 ALT="" SRC="<%=$fsurl%>images/black-gradient.png" HEIGHT="13" WIDTH="100%"></TD>
+        <TD COLSPAN=5 WIDTH="100%" STYLE="padding:0"><IMG BORDER=0 ALT="" SRC="<%=$fsurl%>images/black-gradient.png" HEIGHT="13" WIDTH="100%"></TD>
       </TR>
       </TR>
+
       <TR>
       <TR>
-        <TD COLSPAN=1 BGCOLOR="#000000" ALIGN="right" WIDTH="15%">
+
+        <TD COLSPAN=1 BGCOLOR="#000000" ALIGN="right">
           <FORM ACTION="<%=$fsurl%>edit/cust_main.cgi" METHOD="GET" STYLE="margin:0">
           <FORM ACTION="<%=$fsurl%>edit/cust_main.cgi" METHOD="GET" STYLE="margin:0">
-            <INPUT TYPE="submit" VALUE="New customer">
+            <INPUT TYPE="submit" VALUE="New customer" CLASS="fsblackbutton" onMouseOver="this.className='fsblackbuttonselected'; return true;" onMouseOut="this.className='fsblackbutton'; return true;" STYLE="vertical-align:bottom">
           </FORM>
         </TD>
           </FORM>
         </TD>
+
         <TD COLSPAN=1 BGCOLOR="#000000" ALIGN="right">
           <FORM ACTION="<%=$fsurl%>search/cust_main.cgi" METHOD="GET" STYLE="margin:0">
         <TD COLSPAN=1 BGCOLOR="#000000" ALIGN="right">
           <FORM ACTION="<%=$fsurl%>search/cust_main.cgi" METHOD="GET" STYLE="margin:0">
-            <INPUT NAME="search_cust" TYPE="text" VALUE="(cust #, name or company)" SIZE="22" onFocus="clearhint_search_cust(this);" onClick="clearhint_search_cust(this);" STYLE="text-align:right">
-            <INPUT TYPE="submit" VALUE="Search customers">
+            <INPUT NAME="search_cust" TYPE="text" VALUE="(cust #, name, company or phone)" SIZE="28" onFocus="clearhint_search_cust(this);" onClick="clearhint_search_cust(this);" STYLE="vertical-align:bottom;text-align:right"><BR>
+            <A HREF="<%=$fsurl%>search/cust_main.html" STYLE="color: #000000; font-size: 70%">Advanced</A>
+            <INPUT TYPE="submit" VALUE="Search customers" CLASS="fsblackbutton" onMouseOver="this.className='fsblackbuttonselected'; return true;" onMouseOut="this.className='fsblackbutton'; return true;" STYLE="font-size:70%">
           </FORM>
         </TD>
           </FORM>
         </TD>
+
+        <TD COLSPAN=1 BGCOLOR="#000000" ALIGN="right">
+          <% if ( $FS::CurrentUser::CurrentUser->access_right('View invoices') ) { %>
+            <FORM ACTION="<%=$fsurl%>search/cust_bill.html" METHOD="GET" STYLE="margin:0;display:inline">
+              <INPUT NAME="invnum" TYPE="text" VALUE="(inv #)" SIZE="4" onFocus="clearhint_search_invoice(this);" onClick="clearhint_search_invoice(this);" STYLE="vertical-align:bottom;text-align:right;margin-bottom:1px">
+              <% if ( $FS::CurrentUser::CurrentUser->access_right('List invoices') ) { %>
+                <A HREF="<%=$fsurl%>search/report_cust_bill.html" STYLE="color: #ffffff; font-size: 70%">Advanced</A>
+              <% } %>
+              <BR>
+              <INPUT TYPE="submit" VALUE="Search invoices" CLASS="fsblackbutton" onMouseOver="this.className='fsblackbuttonselected'; return true;" onMouseOut="this.className='fsblackbutton'; return true;" STYLE="font-size:70%">
+            </FORM>
+          <% } %>
+        </TD>
+
         <TD COLSPAN=1 BGCOLOR="#000000" ALIGN="right">
           <FORM ACTION="<%=$fsurl%>search/svc_Smart.html" METHOD="GET" STYLE="margin:0">
         <TD COLSPAN=1 BGCOLOR="#000000" ALIGN="right">
           <FORM ACTION="<%=$fsurl%>search/svc_Smart.html" METHOD="GET" STYLE="margin:0">
-            <INPUT NAME="search_svc" TYPE="text" VALUE="(user, user@domain or domain)" SIZE="26" onFocus="clearhint_search_svc(this);" onClick="clearhint_search_svc(this);" STYLE="text-align:right">
-            <INPUT TYPE="submit" VALUE="Search services">
+            <INPUT NAME="search_svc" TYPE="text" VALUE="(user, user@domain or domain)" SIZE="26" onFocus="clearhint_search_svc(this);" onClick="clearhint_search_svc(this);" STYLE="vertical-align:bottom;text-align:right"><BR>
+            <A HREF="<%=$fsurl%>search/svc_Smarter.html" STYLE="color: #000000; font-size: 70%">Advanced</A>
+            <INPUT TYPE="submit" VALUE="Search services"CLASS="fsblackbutton" onMouseOver="this.className='fsblackbuttonselected'; return true;" onMouseOut="this.className='fsblackbutton'; return true;" STYLE="font-size:70%">
           </FORM>
         </TD>
           </FORM>
         </TD>
-        <TD COLSPAN=1 BGCOLOR="#000000" ALIGN="right">
+
+        <TD COLSPAN=1 BGCOLOR="#000000" ALIGN="right" STYLE="padding-right:4px">
           <FORM ACTION="<%=$fsurl%>rt/index.html" METHOD="GET" STYLE="margin:0">
           <FORM ACTION="<%=$fsurl%>rt/index.html" METHOD="GET" STYLE="margin:0">
-            <INPUT NAME="q" TYPE="text" VALUE="(ticket # or subject string)" onFocus="clearhint_search_ticket(this);" onClick="clearhint_search_ticket(this);" STYLE="text-align:right">
-            <INPUT TYPE="submit" VALUE="Search tickets">
+            <INPUT NAME="q" TYPE="text" VALUE="(ticket # or subject string)" onFocus="clearhint_search_ticket(this);" onClick="clearhint_search_ticket(this);" STYLE="vertical-align:bottom;text-align:right"><BR>
+            <A HREF="<%=$fsurl%>rt/Search/Build.html" STYLE="color: #ffffff; font-size: 70%">Advanced</A>
+            <INPUT TYPE="submit" VALUE="Search tickets" CLASS="fsblackbutton" onMouseOver="this.className='fsblackbuttonselected'; return true;" onMouseOut="this.className='fsblackbutton'; return true;" STYLE="font-size:70%;padding-left:2px;padding-right:2px">
           </FORM>
         </TD>
           </FORM>
         </TD>
+
       </TR>
     </TABLE>
     <TABLE WIDTH="100%" HEIGHT="100%" CELLSPACING=0 CELLPADDING=4>
       </TR>
     </TABLE>
     <TABLE WIDTH="100%" HEIGHT="100%" CELLSPACING=0 CELLPADDING=4>
diff --git a/httemplate/elements/search-cust_main.html b/httemplate/elements/search-cust_main.html
new file mode 100644 (file)
index 0000000..ca91b40
--- /dev/null
@@ -0,0 +1,163 @@
+<%
+  my( %opt ) = @_;
+  $opt{'field_name'} ||= 'custnum';
+
+  my $cust_main = '';
+  if ( $opt{'value'} ) {
+    $cust_main = qsearchs(
+      'table'     => 'cust_main',
+      'hashref'   => { 'custnum' => $opt{'value'} },
+      'extra_sql' => " AND ". $FS::CurrentUser::CurrentUser->agentnums_sql,
+    );
+  }
+%>
+
+<INPUT TYPE="hidden" NAME="<%= $opt{'field_name'} %>" VALUE="<%= $opt{'value'} %>">
+
+<!-- some false laziness w/ misc/batch-cust_pay.html, though not as bad as i'd thought at first... -->
+
+<INPUT TYPE="text" NAME="<%= $opt{'field_name'} %>_search" ID="<%= $opt{'field_name'} %>_search" SIZE="32" VALUE="<%= $cust_main ? $cust_main->name : '(cust #, name or company)' %>" onFocus="clearhint_<%= $opt{'field_name'} %>_search(this);" onClick="clearhint_<%= $opt{'field_name'} %>_search(this);" onChange="smart_<%= $opt{'field_name'} %>_search(this);">
+
+<SELECT NAME="<%= $opt{'field_name'} %>_select" ID="<%= $opt{'field_name'} %>_select" STYLE="color:#ff0000; display:none" onChange="select_<%= $opt{'field_name'} %>(this);">
+</SELECT>
+
+<%= include('/elements/xmlhttp.html',
+              'url'  => $p. 'misc/xmlhttp-cust_main-search.cgi',
+              'subs' => [ 'smart_search' ],
+           )
+%>
+
+<SCRIPT TYPE="text/javascript">
+
+  function clearhint_<%= $opt{'field_name'} %>_search (what) {
+
+    what.style.color = '#000000';
+
+    if ( what.value == '(cust #, name or company)' )
+      what.value = '';
+
+    if ( what.value.indexOf('Customer not found: ') == 0 )
+      what.value = what.value.substr(20);
+
+  }
+
+  function smart_<%= $opt{'field_name'} %>_search(what) {
+
+    var customer = what.value;
+
+    if ( customer == 'searching...' || customer == ''
+         || customer.indexOf('Customer not found: ') == 0 )
+      return;
+
+    if ( what.getAttribute('magic') == 'nosearch' ) {
+      what.setAttribute('magic', '');
+      return;
+    }
+
+    //what.value = 'searching...'
+    what.disabled = true;
+    what.style.color= '#000000';
+    what.style.backgroundColor = '#dddddd';
+
+    var customer_select = document.getElementById('<%= $opt{'field_name'} %>_select');
+
+    //alert("search for customer " + customer);
+
+    function <%= $opt{'field_name'} %>_search_update(customers) {
+
+      //alert('customers returned: ' + customers);
+
+      var customerArray = eval('(' + customers + ')');
+
+      what.disabled = false;
+      what.style.backgroundColor = '#ffffff';
+
+      if ( customerArray.length == 0 ) {
+
+        what.form.<%= $opt{'field_name'} %>.value = '';
+
+        what.value = 'Customer not found: ' + what.value;
+        what.style.color = '#ff0000';
+
+        what.style.display = '';
+        customer_select.style.display = 'none';
+
+      } else if ( customerArray.length == 1 ) {
+
+        //alert('one customer found: ' + customerArray[0]);
+
+        what.form.<%= $opt{'field_name'} %>.value = customerArray[0][0];
+        what.value = customerArray[0][1];
+
+        what.style.display = '';
+        customer_select.style.display = 'none';
+
+      } else {
+
+        //alert('multiple customers found, have to create select dropdown');
+
+        //blank the current list
+        for ( var i = customer_select.length; i >= 0; i-- )
+          customer_select.options[i] = null;
+
+        opt(customer_select, '', 'Multiple customers match "' + customer + '" - select one', '#ff0000');
+
+        //add the multiple customers
+        for ( var s = 0; s < customerArray.length; s++ )
+          opt(customer_select, customerArray[s][0], customerArray[s][1], '#000000');
+
+        opt(customer_select, 'cancel', '(Edit search string)', '#000000');
+
+        what.style.display = 'none';
+        customer_select.style.display = '';
+
+      }
+
+    }
+
+    smart_search( customer, <%= $opt{'field_name'} %>_search_update );
+
+
+  }
+
+  function select_<%= $opt{'field_name'} %> (what) {
+
+    var custnum = what.options[what.selectedIndex].value;
+    var customer = what.options[what.selectedIndex].text;
+
+    var customer_obj = document.getElementById('<%= $opt{'field_name'} %>_search');
+
+    if ( custnum == '' ) {
+      //what.style.color = '#ff0000';
+
+    } else if ( custnum == 'cancel' ) {
+
+      customer_obj.style.color = '#000000';
+
+      what.style.display = 'none';
+      customer_obj.style.display = '';
+      customer_obj.focus();
+
+    } else {
+    
+      what.form.<%= $opt{'field_name'} %>.value = custnum;
+
+      customer_obj.value = customer;
+      customer_obj.style.color = '#000000';
+
+      what.style.display = 'none';
+      customer_obj.style.display = '';
+
+    }
+
+  }
+
+  function opt(what,value,text,color) {
+    var optionName = new Option(text, value, false, false);
+    optionName.style.color = color;
+    var length = what.length;
+    what.options[length] = optionName;
+  }
+
+</SCRIPT>
+
diff --git a/rt/html/Elements/FreesideInvoiceSearch b/rt/html/Elements/FreesideInvoiceSearch
new file mode 100644 (file)
index 0000000..3842b2f
--- /dev/null
@@ -0,0 +1,20 @@
+% if ( $FS::CurrentUser::CurrentUser->access_right('View invoices') ) {
+
+  <form action="<% $RT::URI::freeside::URL %>/search/cust_bill.html" STYLE="margin:0">
+      <SCRIPT TYPE="text/javascript">
+        function clearhint_search_invoice (what) {
+          if ( what.value == '(inv #)' )
+            what.value = '';
+        }
+      </SCRIPT>
+  <input name="invnum" accesskey="0" VALUE="(inv #)" SIZE="4" onFocus="clearhint_search_invoice(this);" onClick="clearhint_search_invoice(this);" STYLE="text-align:right; margin-bottom:1px; font-family: Arial, Verdana, Helvetica, sans-serif;">
+  
+% if ( $FS::CurrentUser::CurrentUser->access_right('List invoices') ) {
+  <A HREF="<% $RT::URI::freeside::URL %>search/report_cust_bill.html" STYLE="color: #ffffff; font-size: 70%; font-weight:normal">Advanced</A>
+% } 
+  <BR>
+  
+  <input type="submit" value="<&|/l&>Search invoices</&>" CLASS="fsblackbutton" onMouseOver="this.className='fsblackbuttonselected'; return true;" onMouseOut="this.className='fsblackbutton'; return true;" STYLE="font-size:70%">
+  </form>
+
+% }
index af8f9f1..c752437 100644 (file)
@@ -1,3 +1,3 @@
 <form action="<% $RT::URI::freeside::URL %>/edit/cust_main.cgi" STYLE="margin:0">
 <form action="<% $RT::URI::freeside::URL %>/edit/cust_main.cgi" STYLE="margin:0">
-<INPUT TYPE="submit" VALUE="<&|/l&>New customer</&>">&nbsp;
+<INPUT TYPE="submit" VALUE="<&|/l&>New customer</&>" CLASS="fsblackbutton" onMouseOver="this.className='fsblackbuttonselected'; return true;" onMouseOut="this.className='fsblackbutton'; return true;">&nbsp;
 </FORM>
 </FORM>
index f0efb60..99b8da0 100644 (file)
@@ -1,10 +1,11 @@
 <form action="<% $RT::URI::freeside::URL %>/search/cust_main.cgi" STYLE="margin:0">
     <SCRIPT TYPE="text/javascript">
       function clearhint_search_cust (what) {
 <form action="<% $RT::URI::freeside::URL %>/search/cust_main.cgi" STYLE="margin:0">
     <SCRIPT TYPE="text/javascript">
       function clearhint_search_cust (what) {
-        if ( what.value = '(cust #, name or company)' )
+        if ( what.value == '(cust #, name, company or phone)' )
           what.value = '';
       }
     </SCRIPT>
           what.value = '';
       }
     </SCRIPT>
-<input name="search_cust" accesskey="0" VALUE="(cust #, name or company)" SIZE="23" onFocus="clearhint_search_cust(this);" onClick="clearhint_search_cust(this);" STYLE="text-align:right">
-<input type="submit" value="<&|/l&>Search customers</&>">&nbsp;
+<input name="search_cust" accesskey="0" VALUE="(cust #, name, company or phone)" SIZE="28" onFocus="clearhint_search_cust(this);" onClick="clearhint_search_cust(this);" STYLE="text-align:right; font-family: Arial, Verdana, Helvetica, sans-serif;"><BR>
+<A HREF="<% $RT::URI::freeside::URL %>/search/cust_main.html" STYLE="color: #000000; font-size: 70%; font-weight:normal">Advanced</A>
+<input type="submit" value="<&|/l&>Search customers</&>" CLASS="fsblackbutton" onMouseOver="this.className='fsblackbuttonselected'; return true;" onMouseOut="this.className='fsblackbutton'; return true;" STYLE="font-size:70%">
 </form>
 </form>
index 47c430f..e9ad564 100644 (file)
@@ -1,10 +1,11 @@
 <form action="<% $RT::URI::freeside::URL %>/search/svc_Smart.html" STYLE="margin:0">
     <SCRIPT TYPE="text/javascript">
       function clearhint_search_svc (what) {
 <form action="<% $RT::URI::freeside::URL %>/search/svc_Smart.html" STYLE="margin:0">
     <SCRIPT TYPE="text/javascript">
       function clearhint_search_svc (what) {
-        if ( what.value = '(user, user@domain or domain)' )
+        if ( what.value == '(user, user@domain or domain)' )
           what.value = '';
       }
     </SCRIPT>
           what.value = '';
       }
     </SCRIPT>
-<input name="search_svc" accesskey="0" VALUE="(user, user@domain or domain)" SIZE="27" onFocus="clearhint_search_svc(this);" onClick="clearhint_search_svc(this);" STYLE="text-align:right">
-<input type="submit" value="<&|/l&>Search services</&>">&nbsp;
+<input name="search_svc" accesskey="0" VALUE="(user, user@domain or domain)" SIZE="26" onFocus="clearhint_search_svc(this);" onClick="clearhint_search_svc(this);" STYLE="text-align:right; font-family: Arial, Verdana, Helvetica, sans-serif;"><BR>
+            <A HREF="<% $RT::URI::freeside::URL %>search/svc_Smarter.html" STYLE="color: #000000; font-size: 70%; font-weight:normal">Advanced</A>
+<input type="submit" value="<&|/l&>Search services</&>" CLASS="fsblackbutton" onMouseOver="this.className='fsblackbuttonselected'; return true;" onMouseOut="this.className='fsblackbutton'; return true;" STYLE="font-size:70%">
 </form>
 </form>
index 52353fa..f13ee0d 100644 (file)
@@ -52,7 +52,7 @@
 %#  </th>
       <span class="topactions">
 % my $notfirst = 0; foreach my $action (sort keys %{$topactions}) {
 %#  </th>
       <span class="topactions">
 % my $notfirst = 0; foreach my $action (sort keys %{$topactions}) {
-        <td class="blackright" ALIGN="right" <% $notfirst++ ? '' : 'WIDTH="15%"' %>>
+        <td class="blackright" ALIGN="right" VALIGN="center">
         <%$topactions->{"$action"}->{'html'} |n %>
         </td>
 % }
         <%$topactions->{"$action"}->{'html'} |n %>
         </td>
 % }
index 55d65fc..e9fc5c6 100644 (file)
 <form action="<% $RT::WebPath %>/index.html" STYLE="margin:0">
 <SCRIPT TYPE="text/javascript">
   function clearhint_search_ticket (what) {
 <form action="<% $RT::WebPath %>/index.html" STYLE="margin:0">
 <SCRIPT TYPE="text/javascript">
   function clearhint_search_ticket (what) {
-    if ( what.value = '(ticket # or subject string)' )
+    if ( what.value == '(ticket # or subject string)' )
       what.value = '';
   }
 </SCRIPT>
       what.value = '';
   }
 </SCRIPT>
-<input name="q" accesskey="0" VALUE="(ticket # or subject string)" onFocus="clearhint_search_ticket(this);" onClick="clearhint_search_ticket(this);" STYLE="text-align:right">
-<input type="submit" value="<&|/l&>Search tickets</&>">&nbsp;
+<input name="q" accesskey="0" VALUE="(ticket # or subject string)" onFocus="clearhint_search_ticket(this);" onClick="clearhint_search_ticket(this);" STYLE="text-align:right; font-family: Arial, Verdana, Helvetica, sans-serif;"><BR>
+<A HREF="<% $RT::WebPath %>/Search/Build.html" STYLE="color: #ffffff; font-size: 70%; font-weight:normal">Advanced</A>
+<input type="submit" value="<&|/l&>Search tickets</&>" CLASS="fsblackbutton" onMouseOver="this.className='fsblackbuttonselected'; return true;" onMouseOut="this.className='fsblackbutton'; return true;" STYLE="font-size:70%;padding-left:2px;padding-right:2px">
 </form>
 </form>
index dcb652e..721f920 100644 (file)
@@ -63,9 +63,11 @@ my $basetopactions = {
                },
        B => { html => $m->scomp('/Elements/FreesideSearch')    
                },
                },
        B => { html => $m->scomp('/Elements/FreesideSearch')    
                },
-       C => { html => $m->scomp('/Elements/FreesideSvcSearch') 
+       C => { html => $m->scomp('/Elements/FreesideInvoiceSearch')     
                },
                },
-       D => { html => $m->scomp('/Elements/SimpleSearch') 
+       D => { html => $m->scomp('/Elements/FreesideSvcSearch') 
+               },
+       E => { html => $m->scomp('/Elements/SimpleSearch') 
                }
        };
 my $basetabs = {
                }
        };
 my $basetabs = {
index 04c959a..5c241f9 100644 (file)
@@ -373,9 +373,44 @@ li.currenttopnav-5-major {
         background-color: #000000;
         color: #ffffff;
         background-position: left top;
         background-color: #000000;
         color: #ffffff;
         background-position: left top;
-        vertical-align: top;
+        vertical-align: center;
         text-align: right;
         text-align: right;
+        font-size:16px;
+        padding-right:4px
          }
          }
+
+input.fsblackbutton {
+        background-color:#333333;
+        color: #ffffff;
+        border:1px solid;
+        border-top-color:#cccccc;
+        border-left-color:#cccccc;
+        border-right-color:#aaaaaa;
+        border-bottom-color:#aaaaaa;
+        font-family: Arial, Verdana, Helvetica, sans-serif;
+        font-weight:bold;
+        padding-left:12px;
+        padding-right:12px;
+        overflow:visible;
+        filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr='#ff333333',EndColorStr='#ff666666')
+}
+
+input.fsblackbuttonselected {
+        background-color:#7e0079;
+        color: #ffffff;
+        border:1px solid;
+        border-top-color:#cccccc;
+        border-left-color:#cccccc;
+        border-right-color:#aaaaaa;
+        border-bottom-color:#aaaaaa;
+        font-family: Arial, Verdana, Helvetica, sans-serif;
+        font-weight:bold;
+        padding-left:12px;
+        padding-right:12px;
+        overflow:visible;
+        filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr='#ff330033',EndColorStr='#ff7e0079')
+}
+
 .mediumgray {
         background-color: #cccccc;
         background-position: left top;
 .mediumgray {
         background-color: #cccccc;
         background-position: left top;
@@ -442,7 +477,7 @@ div.downloadattachment {
 
 
 td {  font-family: Arial, Verdana, Helvetica, sans-serif;
 
 
 td {  font-family: Arial, Verdana, Helvetica, sans-serif;
-        font-size: 11px;
+        font-size: 12px;
         background-position: left top;
          }
 .black { background-color: #000000;
         background-position: left top;
          }
 .black { background-color: #000000;