summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FS/FS/Conf.pm7
-rw-r--r--FS/FS/cust_main.pm91
-rw-r--r--httemplate/elements/header.html40
3 files changed, 95 insertions, 43 deletions
diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm
index a57c4732b..a6a738a75 100644
--- a/FS/FS/Conf.pm
+++ b/FS/FS/Conf.pm
@@ -2113,6 +2113,13 @@ worry that config_items is freeside-specific and icky.
},
{
+ 'key' => 'address1-search',
+ 'section' => 'UI',
+ 'description' => 'Enable the ability to search the address1 field from customer search.',
+ 'type' => 'checkbox',
+ },
+
+ {
'key' => 'address2-search',
'section' => 'UI',
'description' => 'Enable a "Unit" search box which searches the second address field. Useful for multi-tenant applications. See also: cust_main-require_address2',
diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm
index ffc9f0fce..1c6284976 100644
--- a/FS/FS/cust_main.pm
+++ b/FS/FS/cust_main.pm
@@ -2,8 +2,12 @@ package FS::cust_main;
require 5.006;
use strict;
-use vars qw( @ISA @EXPORT_OK $DEBUG $me $conf @encrypted_fields
- $import $skip_fuzzyfiles $ignore_expired_card @paytypes);
+use vars qw( @ISA @EXPORT_OK $DEBUG $me $conf
+ @encrypted_fields
+ $import $ignore_expired_card
+ $skip_fuzzyfiles @fuzzyfields
+ @paytypes
+ );
use vars qw( $realtime_bop_decline_quiet ); #ugh
use Safe;
use Carp;
@@ -77,9 +81,11 @@ $DEBUG = 0;
$me = '[FS::cust_main]';
$import = 0;
-$skip_fuzzyfiles = 0;
$ignore_expired_card = 0;
+$skip_fuzzyfiles = 0;
+@fuzzyfields = ( 'first', 'last', 'company', 'address1' );
+
@encrypted_fields = ('payinfo', 'paycvv');
sub nohistory_fields { ('paycvv'); }
@@ -1492,9 +1498,7 @@ sub queue_fuzzyfiles_update {
my $dbh = dbh;
my $queue = new FS::queue { 'job' => 'FS::cust_main::append_fuzzyfiles' };
- my $error = $queue->insert( map $self->getfield($_),
- qw(first last company)
- );
+ my $error = $queue->insert( map $self->getfield($_), @fuzzyfields );
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
return "queueing job (transaction rolled back): $error";
@@ -1502,9 +1506,7 @@ sub queue_fuzzyfiles_update {
if ( $self->ship_last ) {
$queue = new FS::queue { 'job' => 'FS::cust_main::append_fuzzyfiles' };
- $error = $queue->insert( map $self->getfield("ship_$_"),
- qw(first last company)
- );
+ $error = $queue->insert( map $self->getfield("ship_$_"), @fuzzyfields );
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
return "queueing job (transaction rolled back): $error";
@@ -4457,9 +4459,9 @@ sub realtime_bop {
sub _bop_recurring_billing {
my( $self, %opt ) = @_;
- my $method = $conf->config('credit_card-recurring_billing_flag');
+ my $method = scalar($conf->config('credit_card-recurring_billing_flag'));
- if ( $method eq 'transaction_is_recur' ) {
+ if ( defined($method) && $method eq 'transaction_is_recur' ) {
return 1 if $opt{'trans_is_recur'};
@@ -8443,8 +8445,8 @@ sub process_email_search_sql {
=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, I<first>, I<last> and/or I<company> may be specified (the
-appropriate ship_ field is also searched).
+records. Currently, I<first>, I<last>, I<company> and/or I<address1> may be
+specified (the appropriate ship_ field is also searched).
Additional options are the same as FS::Record::qsearch
@@ -8573,15 +8575,18 @@ sub smart_search {
}
if ( $search =~ /^\s*(\d+)\s*$/
- || ( $conf->config('cust_main-agent_custid-format') eq 'ww?d+'
- && $search =~ /^\s*(\w\w?\d+)\s*$/
- )
- )
+ || ( $conf->config('cust_main-agent_custid-format') eq 'ww?d+'
+ && $search =~ /^\s*(\w\w?\d+)\s*$/
+ )
+ || ( $conf->exists('address1-search' )
+ && $search =~ /^\s*(\d+\-?\w*)\s*$/ #i.e. 1234A or 9432-D
+ )
+ )
{
my $num = $1;
- if ( $num <= 2147483647 ) { #need a bigint custnum? wow.
+ if ( $num =~ /^(\d+)$/ && $num <= 2147483647 ) { #need a bigint custnum? wow
push @cust_main, qsearch( {
'table' => 'cust_main',
'hashref' => { 'custnum' => $num, %options },
@@ -8595,13 +8600,28 @@ sub smart_search {
'extra_sql' => " AND $agentnums_sql", #agent virtualization
} );
+ if ( $conf->exists('address1-search') ) {
+ my $len = length($num);
+ $num = lc($num);
+ foreach my $prefix ( '', 'ship_' ) {
+ push @cust_main, qsearch( {
+ 'table' => 'cust_main',
+ 'hashref' => { %options, },
+ 'extra_sql' =>
+ ( keys(%options) ? ' AND ' : ' WHERE ' ).
+ " LOWER(SUBSTRING(${prefix}address1 FROM 1 FOR $len)) = '$num' ".
+ " AND $agentnums_sql",
+ } );
+ }
+ }
+
} 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
+ #so just do an exact (but case-insensitive) search
foreach my $prefix ( '', 'ship_' ) {
push @cust_main, qsearch( {
@@ -8670,11 +8690,16 @@ sub smart_search {
#exact
my $sql = scalar(keys %options) ? ' AND ' : ' WHERE ';
- $sql .= " ( LOWER(last) = $q_value
- OR LOWER(company) = $q_value
- OR LOWER(ship_last) = $q_value
- OR LOWER(ship_company) = $q_value
- )";
+ $sql .= " ( LOWER(last) = $q_value
+ OR LOWER(company) = $q_value
+ OR LOWER(ship_last) = $q_value
+ OR LOWER(ship_company) = $q_value
+ ";
+ $sql .= " OR LOWER(address1) = $q_value
+ OR LOWER(ship_address1) = $q_value
+ "
+ if $conf->exists('address1-search');
+ $sql .= " )";
push @cust_main, qsearch( {
'table' => 'cust_main',
@@ -8715,6 +8740,13 @@ sub smart_search {
;
}
+ if ( $conf->exists('address1-search') ) {
+ push @hashrefs,
+ { 'address1' => { op=>'ILIKE', value=>"%$value%" }, },
+ { 'ship_address1' => { op=>'ILIKE', value=>"%$value%" }, },
+ ;
+ }
+
foreach my $hashref ( @hashrefs ) {
push @cust_main, qsearch( {
@@ -8745,6 +8777,10 @@ sub smart_search {
push @cust_main,
FS::cust_main->fuzzy_search( { $field => $value }, @fuzopts );
}
+ if ( $conf->exists('address1-search') ) {
+ push @cust_main,
+ FS::cust_main->fuzzy_search( { 'address1' => $value }, @fuzopts );
+ }
}
@@ -8828,9 +8864,6 @@ sub email_search {
=cut
-use vars qw(@fuzzyfields);
-@fuzzyfields = ( 'last', 'first', 'company' );
-
sub check_and_rebuild_fuzzyfiles {
my $dir = $FS::UID::conf_dir. "/cache.". $FS::UID::datasrc;
rebuild_fuzzyfiles() if grep { ! -e "$dir/cust_main.$_" } @fuzzyfields
@@ -8890,7 +8923,7 @@ sub all_X {
\@array;
}
-=item append_fuzzyfiles LASTNAME COMPANY
+=item append_fuzzyfiles FIRSTNAME LASTNAME COMPANY ADDRESS1
=cut
@@ -8903,7 +8936,7 @@ sub append_fuzzyfiles {
my $dir = $FS::UID::conf_dir. "/cache.". $FS::UID::datasrc;
- foreach my $field (qw( first last company )) {
+ foreach my $field (@fuzzyfields) {
my $value = shift;
if ( $value ) {
diff --git a/httemplate/elements/header.html b/httemplate/elements/header.html
index b9ddc7369..0e6bbdeb2 100644
--- a/httemplate/elements/header.html
+++ b/httemplate/elements/header.html
@@ -40,27 +40,27 @@ Example:
<SCRIPT TYPE="text/javascript">
function clearhint_search_cust (what) {
- if ( what.value == '(cust #, name, company or contact phone)' )
+ if ( what.value == '<% $cust_label %>' )
what.value = '';
}
function clearhint_search_address2 (what) {
- if ( what.value == '(Unit #)' )
+ if ( what.value == '<% $address2_label %>' )
what.value = '';
}
function clearhint_search_invoice (what) {
- if ( what.value == '(inv #)' )
+ if ( what.value == '<% $inv_label %>' )
what.value = '';
}
function clearhint_search_svc (what) {
- if ( what.value == '(user, email, ip, mac, domain or service phone)' )
+ if ( what.value == '<% $svc_label %>' )
what.value = '';
}
function clearhint_search_ticket (what) {
- if ( what.value == '(ticket #, subject, email or fulltext:text)' )
+ if ( what.value == '<% $ticketing_label %>' )
what.value = '';
}
</SCRIPT>
@@ -196,7 +196,7 @@ input.fstext {
<TD COLSPAN=1 BGCOLOR="#000000" ALIGN="right">
% if ( $curuser->access_right('List customers') ) {
<FORM ACTION="<%$fsurl%>search/cust_main.cgi" METHOD="GET" STYLE="margin:0">
- <INPUT NAME="search_cust" TYPE="text" VALUE="(cust #, name, company or contact phone)" SIZE="37" onFocus="clearhint_search_cust(this);" onClick="clearhint_search_cust(this);" CLASS="fstext"><BR>
+ <INPUT NAME="search_cust" TYPE="text" VALUE="<% $cust_label %>" STYLE="width:<%$cust_width%>px" onFocus="clearhint_search_cust(this);" onClick="clearhint_search_cust(this);" CLASS="fstext"><BR>
<A HREF="<%$fsurl%>search/report_cust_main.html" STYLE="color: #ffffff; font-size: 11px">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:11px">
</FORM>
@@ -207,7 +207,7 @@ input.fstext {
% if ( $conf->exists('address2-search') ) {
<FORM ACTION="<%$fsurl%>search/cust_main.cgi" METHOD="GET" STYLE="margin:0;display:inline">
<INPUT TYPE="hidden" NAME="address2_on" VALUE="1">
- <INPUT NAME="address2_text" TYPE="text" VALUE="(Unit #)" SIZE="4" onFocus="clearhint_search_address2(this);" onClick="clearhint_search_address2(this);" CLASS="fstext">
+ <INPUT NAME="address2_text" TYPE="text" VALUE="<% $address2_label %>" STYLE="width:67px" onFocus="clearhint_search_address2(this);" onClick="clearhint_search_address2(this);" CLASS="fstext">
<BR>
<INPUT TYPE="submit" VALUE="Search units" CLASS="fsblackbutton" onMouseOver="this.className='fsblackbuttonselected'; return true;" onMouseOut="this.className='fsblackbutton'; return true;" STYLE="font-size:11px;padding-left:2px;padding-right:2px">
</FORM>
@@ -216,14 +216,13 @@ input.fstext {
<TD COLSPAN=1 BGCOLOR="#000000" ALIGN="right">
% if ( $curuser->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="5" onFocus="clearhint_search_invoice(this);" onClick="clearhint_search_invoice(this);" CLASS="fstext">
+ <INPUT NAME="invnum" TYPE="text" VALUE="<% $inv_label %>" STYLE="width:64px" onFocus="clearhint_search_invoice(this);" onClick="clearhint_search_invoice(this);" CLASS="fstext">
% if ( $curuser->access_right('List invoices') ) {
- <A HREF="<%$fsurl%>search/report_cust_bill.html" STYLE="color: #ffffff; font-size: 11px">Adv</A>
+ <A HREF="<%$fsurl%>search/report_cust_bill.html" STYLE="color: #ffffff; font-size: 11px">Adv</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:11px;padding-left:1px;padding-right:1px">
+<BR>
+ <INPUT TYPE="submit" VALUE="Search invoices" CLASS="fsblackbutton" onMouseOver="this.className='fsblackbuttonselected'; return true;" onMouseOut="this.className='fsblackbutton'; return true;" STYLE="font-size:11px;padding-left:2px;padding-right:2px">
</FORM>
% }
</TD>
@@ -231,7 +230,7 @@ input.fstext {
<TD COLSPAN=1 BGCOLOR="#000000" ALIGN="right">
% if ( $curuser->access_right('View customer services') ) {
<FORM ACTION="<%$fsurl%>search/cust_svc.html" METHOD="GET" STYLE="margin:0">
- <INPUT NAME="search_svc" TYPE="text" VALUE="(user, email, ip, mac, domain or service phone)" SIZE="41" onFocus="clearhint_search_svc(this);" onClick="clearhint_search_svc(this);" CLASS="fstext"><BR>
+ <INPUT NAME="search_svc" TYPE="text" VALUE="<% $svc_label %>" STYLE="width:324px" onFocus="clearhint_search_svc(this);" onClick="clearhint_search_svc(this);" CLASS="fstext"><BR>
<A NOTYET="<%$fsurl%>search/svc_Smarter.html" STYLE="color: #000000; font-size:11px">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:11px">
</FORM>
@@ -241,7 +240,7 @@ input.fstext {
<TD COLSPAN=1 BGCOLOR="#000000" ALIGN="right" STYLE="padding-left:4px;padding-right:4px">
% if ( $conf->config("ticket_system") ) {
<FORM ACTION="<% FS::TicketSystem->baseurl %>index.html" METHOD="GET" STYLE="margin:0">
- <INPUT NAME="q" TYPE="text" VALUE="(ticket #, subject, email or fulltext:text)" SIZE=33 onFocus="clearhint_search_ticket(this);" onClick="clearhint_search_ticket(this);" CLASS="fstext"><BR>
+ <INPUT NAME="q" TYPE="text" VALUE="<% $ticketing_label %>" STYLE="width:256px" onFocus="clearhint_search_ticket(this);" onClick="clearhint_search_ticket(this);" CLASS="fstext"><BR>
<A HREF="<% FS::TicketSystem->baseurl %>Search/Build.html" STYLE="color: #ffffff; font-size:11px">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:11px">
</FORM>
@@ -335,4 +334,17 @@ if ( scalar(@agentnums) == 1 ) {
$company_name = $conf->config('company_name');
}
+my $cust_width = 288; #251 #ok for IE, slightly bigger for windows firefox
+my $cust_label = '(cust #, name, company';
+if ( $conf->exists('address1-search') ) {
+ $cust_label .= ', address';
+ $cust_width += 64;
+}
+$cust_label .= ' or contact phone)';
+
+my $address2_label = '(Unit #)';
+my $inv_label = '(inv #)';
+my $svc_label = '(user, email, ip, mac, domain or service phone)';
+my $ticketing_label = '(ticket #, subject, email or fulltext:text)';
+
</%init>